Strings and Runes in Lisp

(defpackage :strings-and-runes
  (:use :cl))

(in-package :strings-and-runes)

(defun main ()
  ;; `s` is a string assigned a literal value
  ;; representing the word "hello" in the Thai
  ;; language. Lisp string literals are typically
  ;; UTF-8 encoded text.
  (defparameter *s* "สวัสดี")

  ;; In Lisp, we can get the length of a string using the
  ;; `length` function. This will return the number of characters,
  ;; not the number of bytes.
  (format t "Len: ~A~%" (length *s*))

  ;; To iterate over the characters in a string, we can use
  ;; the `loop` macro with `across`.
  (format t "Characters: ")
  (loop for char across *s*
        do (format t "~A " (char-code char)))
  (terpri)

  ;; In Common Lisp, there's no built-in function to count
  ;; Unicode code points. We can create a custom function
  ;; for this purpose.
  (defun unicode-char-count (string)
    (length (remove-if-not #'characterp string)))

  (format t "Unicode char count: ~A~%" (unicode-char-count *s*))

  ;; We can use `loop` with `for` and `across` to iterate
  ;; over characters in a string.
  (loop for char across *s*
        for i from 0
        do (format t "U+~4,'0X '~A' starts at ~D~%"
                   (char-code char) char i))

  ;; Common Lisp doesn't have a direct equivalent to Go's
  ;; DecodeRuneInString, but we can iterate over characters
  ;; using similar logic.
  (format t "~%Using character iteration~%")
  (loop for i from 0 below (length *s*)
        for char = (char *s* i)
        do (progn
             (format t "U+~4,'0X '~A' starts at ~D~%"
                     (char-code char) char i)
             (examine-char char))))

(defun examine-char (c)
  ;; In Common Lisp, we can compare characters directly.
  (cond ((char= c #\t)
         (format t "found tee~%"))
        ((char= c #\ส)
         (format t "found so sua~%"))))

;; Call the main function
(main)

This Lisp code demonstrates concepts similar to those in the original Go example:

  1. We define a string containing Thai characters.
  2. We show how to get the length of a string (which in Lisp gives the number of characters, not bytes).
  3. We iterate over the characters in the string, printing their Unicode code points.
  4. We create a custom function to count Unicode characters (since Lisp doesn’t have a direct equivalent to Go’s RuneCountInString).
  5. We demonstrate iterating over characters in a string, showing their Unicode code points and positions.
  6. We create an examine-char function to demonstrate character comparison.

When you run this program, it will output similar information to the Go version, but adapted for Lisp’s string handling:

Len: 6
Characters: 3626 3623 3633 3626 3604 3637 
Unicode char count: 6
U+0E2A 'ส' starts at 0
U+0E27 'ว' starts at 1
U+0E31 'ั' starts at 2
U+0E2A 'ส' starts at 3
U+0E14 'ด' starts at 4
U+0E35 'ี' starts at 5

Using character iteration
U+0E2A 'ส' starts at 0
found so sua
U+0E27 'ว' starts at 1
U+0E31 'ั' starts at 2
U+0E2A 'ส' starts at 3
found so sua
U+0E14 'ด' starts at 4
U+0E35 'ี' starts at 5

This example demonstrates how Lisp handles strings and characters, which are somewhat different from Go’s concepts of strings and runes. Lisp strings are sequences of characters, and each character can represent a full Unicode code point.