LISP - Strings
Lisp - Strings
Section titled “Lisp - Strings”In Common Lisp, strings are a specialized type of vector, specifically a one-dimensional array whose elements are characters. This structure makes them a sequence, allowing many powerful sequence-manipulation functions to operate on them directly.
String literals are created by enclosing a sequence of characters in double quotes ("). Special characters, such as the double quote itself or the backslash (\), must be escaped with a preceding backslash. For example, "This is a \"quoted\" string.".
Basic String Operations
Section titled “Basic String Operations”Let’s start with some fundamental string operations. Create a new source file named main.lisp and add the following code. A modern Lisp development workflow often involves an interactive REPL (Read-Eval-Print Loop), where you can evaluate these expressions one by one.
Example: Creating and Printing Strings
Section titled “Example: Creating and Printing Strings”;; The `write-line` function prints a string followed by a newline.(write-line "Hello, Modern Lisp!")
;; The `format` function is a more powerful tool for creating formatted strings.;; `~a` is a placeholder for an argument, and `~%` is a newline character.(format t "Welcome to ~a!~%" "the Lisp Tutorial")
;; Escaping special characters(write-line "This demonstrates \"escaping\" inside a string.")Output
Section titled “Output”Hello, Modern Lisp!Welcome to the Lisp Tutorial!This demonstrates "escaping" inside a string.String Comparison
Section titled “String Comparison”Numeric comparison operators like < and > do not work on strings. Common Lisp provides a dedicated set of functions for lexicographical string comparison, with both case-sensitive and case-insensitive variants.
| Case-Sensitive Function | Case-Insensitive Function | Description |
|---|---|---|
string= | string-equal | Returns T if all argument strings are identical. |
string/= | string-not-equal | Returns the index of the first mismatch, or NIL if any two strings are identical. |
string< | string-lessp | Returns the index of the first mismatch if strings are in strictly ascending lexicographical order, else NIL. |
string> | string-greaterp | Returns the index of the first mismatch if strings are in strictly descending lexicographical order, else NIL. |
string<= | string-not-greaterp | Returns the index of the first mismatch if strings are in ascending (or equal) lexicographical order, else NIL. |
string>= | string-not-lessp | Returns the index of the first mismatch if strings are in descending (or equal) lexicographical order, else NIL. |
Example: Comparing Strings
Section titled “Example: Comparing Strings”Let’s explore how these comparison functions work in practice.
;; Case-sensitive equality check(format t "'alpha' = 'Alpha' -> ~a~%" (string= "alpha" "Alpha"))
;; Case-insensitive equality check(format t "'alpha' equal 'Alpha' -> ~a~%" (string-equal "alpha" "Alpha"))
;; Less-than check (case-sensitive);; 'A' comes before 'a' in ASCII/Unicode(format t "'Alpha' < 'alpha' -> ~a~%" (string< "Alpha" "alpha"))
;; Mismatch check;; The mismatch occurs at index 3 ('h' vs 'a')(format t "'Lisp' /= 'Lisa' -> ~a~%" (string/= "Lisp" "Lisa"))
;; No mismatch returns NIL for inequality checks(format t "'test' /= 'test' -> ~a~%" (string/= "test" "test"))Output
Section titled “Output”'alpha' = 'Alpha' -> NIL'alpha' equal 'Alpha' -> T'Alpha' < 'alpha' -> 0'Lisp' /= 'Lisa' -> 3'test' /= 'test' -> NILCase Conversion
Section titled “Case Conversion”Common Lisp provides simple functions for controlling the case of characters within a string.
| Function | Description |
|---|---|
string-upcase | Returns a new string with all alphabetic characters converted to uppercase. |
string-downcase | Returns a new string with all alphabetic characters converted to lowercase. |
string-capitalize | Returns a new string with the first letter of each word capitalized. |
Example: Case Conversion
Section titled “Example: Case Conversion”(let ((my-string "a modern lisp tutorial")) (write-line (string-upcase my-string)) (write-line (string-capitalize my-string)))Output
Section titled “Output”A MODERN LISP TUTORIALA Modern Lisp TutorialTrimming Whitespace
Section titled “Trimming Whitespace”These functions are useful for cleaning up user input or data from files by removing unwanted characters from the beginning or end of a string.
| Function | Description |
|---|---|
string-trim | Removes all characters from the character-bag from both the beginning and end of the string. |
string-left-trim | Removes characters from the character-bag from the beginning (left side) of the string. |
string-right-trim | Removes characters from the character-bag from the end (right side) of the string. |
Example: Trimming Strings
Section titled “Example: Trimming Strings”The first argument to these functions is a sequence of characters to be removed, often called a ‘character-bag’.
(let* ((char-bag '(#\Space #\Tab #\Newline)) (messy-string " some text")) (format t "Original: '~a'~%" messy-string) (format t "Trimmed: '~a'~%" (string-trim char-bag messy-string)) (format t "Left-Trimmed: '~a'~%" (string-left-trim char-bag messy-string)) (format t "Right-Trimmed: '~a'~%" (string-right-trim char-bag messy-string)))Output
Section titled “Output”Original: ' some text'Trimmed: 'some text'Left-Trimmed: 'some text'Right-Trimmed: ' some text'Core Sequence Functions on Strings
Section titled “Core Sequence Functions on Strings”Since strings are sequences, a wide range of powerful functions can be used on them. Here are some of the most common ones.
Length, Subsequence, and Character Access
Section titled “Length, Subsequence, and Character Access”(let ((s "Hello World")) ;; `length` returns the number of characters in the string. (format t "Length: ~d~%" (length s))
;; `subseq` extracts a part of the string. Indices are 0-based. ;; This extracts from index 6 to the end. (format t "Substring: ~s~%" (subseq s 6))
;; `char` accesses a single character at a specific index. (format t "Character at index 6: ~c~%" (char s 6)))Output
Section titled “Output”Length: 11Substring: "World"Character at index 6: WSorting, Reversing, and Concatenating
Section titled “Sorting, Reversing, and Concatenating”These operations demonstrate the power of treating strings as sequences.
;; `sort` sorts a sequence. It's destructive, so we sort a copy.;; `char<` is the predicate used for comparison.(let ((original "ecbda")) (let ((sorted (sort (copy-seq original) #'char<))) (format t "Sorted '~a' -> '~a'~%" original sorted)))
;; `reverse` reverses the order of elements in a sequence.(write-line (reverse "live"))
;; `concatenate` joins sequences. The first argument specifies the result type.(write-line (concatenate 'string "Hello, " "Lisp " "World!"))Output
Section titled “Output”Sorted 'ecbda' -> 'abcde'evilHello, Lisp World!Best Practices and Further Learning
Section titled “Best Practices and Further Learning”- Use
formatfor complex construction: Whileconcatenateis good for simple joining,formatis more flexible and readable for building complex strings from various data types. - Understand string immutability: Functions like
string-upcaseorreversereturn a new string. Destructive functions likesortshould be used with caution, typically on acopy-seqof the original string to avoid unexpected side effects. - Explore string libraries: For advanced needs like regular expressions, consider using a library from Quicklisp, the de-facto package manager for Common Lisp. A popular choice is
cl-ppcre.