LISP - 字符串
Lisp - 字符串
Section titled “Lisp - 字符串”在 Common Lisp 中,字符串 (strings) 是一种特殊的向量 (vector) 类型,具体来说,它是一个元素为字符的一维数组。这种结构使其成为序列 (sequence),允许许多强大的序列操作函数直接对其进行操作。
字符串字面量 (String literals) 通过将字符序列用双引号 (") 括起来创建。特殊字符,例如双引号本身或反斜杠 (\),必须用前导反斜杠进行转义 (escape)。例如,"This is a \"quoted\" string."。
基本字符串操作
Section titled “基本字符串操作”让我们从一些基本的字符串操作开始。创建一个名为 main.lisp 的新源文件,并添加以下代码。现代 Lisp 开发工作流程通常涉及交互式 REPL(读取-求值-打印循环),你可以在其中逐一评估这些表达式。
示例:创建和打印字符串
Section titled “示例:创建和打印字符串”;; `write-line` 函数打印一个字符串,然后是换行符。(write-line "Hello, Modern Lisp!")
;; `format` 函数是创建格式化字符串的更强大工具。;; `~a` 是参数的占位符,`~%` 是换行符。(format t "Welcome to ~a!~%" "the Lisp Tutorial")
;; 转义特殊字符(write-line "This demonstrates \"escaping\" inside a string.")Hello, Modern Lisp!Welcome to the Lisp Tutorial!This demonstrates "escaping" inside a string.像 < 和 > 这样的数值比较运算符不适用于字符串。Common Lisp 提供了一组专门用于字典序字符串比较的函数,包括区分大小写和不区分大小写的变体。
| 区分大小写函数 | 不区分大小写函数 | 描述 |
|---|---|---|
string= | string-equal | 如果所有参数字符串都相同,则返回 T。 |
string/= | string-not-equal | 返回第一个不匹配的索引,如果任何两个字符串相同则返回 NIL。 |
string< | string-lessp | 如果字符串按严格升序的字典序排列,则返回第一个不匹配的索引,否则返回 NIL。 |
string> | string-greaterp | 如果字符串按严格降序的字典序排列,则返回第一个不匹配的索引,否则返回 NIL。 |
string<= | string-not-greaterp | 如果字符串按升序(或相等)的字典序排列,则返回第一个不匹配的索引,否则返回 NIL。 |
string>= | string-not-lessp | 如果字符串按降序(或相等)的字典序排列,则返回第一个不匹配的索引,否则返回 NIL。 |
示例:比较字符串
Section titled “示例:比较字符串”让我们看看这些比较函数在实践中如何工作。
;; 区分大小写的相等检查(format t "'alpha' = 'Alpha' -> ~a~%" (string= "alpha" "Alpha"))
;; 不区分大小写的相等检查(format t "'alpha' equal 'Alpha' -> ~a~%" (string-equal "alpha" "Alpha"))
;; 小于检查(区分大小写);; 在 ASCII/Unicode 中 'A' 排在 'a' 之前(format t "'Alpha' < 'alpha' -> ~a~%" (string< "Alpha" "alpha"))
;; 不匹配检查;; 不匹配发生在索引 3 处('h' 对 'a')(format t "'Lisp' /= 'Lisa' -> ~a~%" (string/= "Lisp" "Lisa"))
;; 不等式检查中,不匹配返回 NIL(format t "'test' /= 'test' -> ~a~%" (string/= "test" "test"))'alpha' = 'Alpha' -> NIL'alpha' equal 'Alpha' -> T'Alpha' < 'alpha' -> 0'Lisp' /= 'Lisa' -> 3'test' /= 'test' -> NILCommon Lisp 提供了简单的函数来控制字符串中字符的大小写。
| 函数 | 描述 |
|---|---|
string-upcase | 返回一个新字符串,其中所有字母字符都转换为大写。 |
string-downcase | 返回一个新字符串,其中所有字母字符都转换为小写。 |
string-capitalize | 返回一个新字符串,其中每个单词的首字母大写。 |
示例:大小写转换
Section titled “示例:大小写转换”(let ((my-string "a modern lisp tutorial")) (write-line (string-upcase my-string)) (write-line (string-capitalize my-string)))A MODERN LISP TUTORIALA Modern Lisp Tutorial修剪空白字符
Section titled “修剪空白字符”这些函数对于清理用户输入或文件数据很有用,通过移除字符串开头或结尾不需要的字符。
| 函数 | 描述 |
|---|---|
string-trim | 从字符串的开头和结尾移除 character-bag 中所有字符。 |
string-left-trim | 从字符串的开头(左侧)移除 character-bag 中的字符。 |
string-right-trim | 从字符串的结尾(右侧)移除 character-bag 中的字符。 |
示例:修剪字符串
Section titled “示例:修剪字符串”这些函数的第一个参数是要移除的字符序列,通常称为“字符袋 (character-bag)”。
(let* ((char-bag '(#\Space #\Tab #\Newline)) (messy-string " some text")) (format t "原始字符串:'~a'~%" messy-string) (format t "修剪后:'~a'~%" (string-trim char-bag messy-string)) (format t "左侧修剪后:'~a'~%" (string-left-trim char-bag messy-string)) (format t "右侧修剪后:'~a'~%" (string-right-trim char-bag messy-string)))Original: ' some text'Trimmed: 'some text'Left-Trimmed: 'some text'Right-Trimmed: ' some text'字符串上的核心序列函数
Section titled “字符串上的核心序列函数”由于字符串是序列,因此可以在其上使用各种强大的函数。以下是一些最常用的函数。
长度、子序列和字符访问
Section titled “长度、子序列和字符访问”(let ((s "Hello World")) ;; `length` 返回字符串中的字符数。 (format t "Length: ~d~%" (length s))
;; `subseq` 提取字符串的一部分。索引是基于 0 的。 ;; 这将从索引 6 提取到字符串末尾。 (format t "Substring: ~s~%" (subseq s 6))
;; `char` 访问特定索引处的单个字符。 (format t "Character at index 6: ~c~%" (char s 6)))Length: 11Substring: "World"Character at index 6: W排序、反转和连接
Section titled “排序、反转和连接”这些操作展示了将字符串视为序列的强大功能。
;; `sort` 对序列进行排序。它是破坏性的,因此我们排序一个副本。;; `char<` 是用于比较的谓词。(let ((original "ecbda")) (let ((sorted (sort (copy-seq original) #'char<))) (format t "Sorted '~a' -> '~a'~%" original sorted)))
;; `reverse` 反转序列中元素的顺序。(write-line (reverse "live"))
;; `concatenate` 连接序列。第一个参数指定结果类型。(write-line (concatenate 'string "Hello, " "Lisp " "World!"))Sorted 'ecbda' -> 'abcde'evilHello, Lisp World!最佳实践与深入学习
Section titled “最佳实践与深入学习”- 使用
format进行复杂构建:虽然concatenate适用于简单的连接,但format在从各种数据类型构建复杂字符串时更加灵活和可读。 - 理解字符串不可变性:像
string-upcase或reverse这样的函数返回一个新字符串。像sort这样的破坏性函数应谨慎使用,通常在原始字符串的copy-seq(副本)上使用,以避免意外的副作用 (side effects)。 - 探索字符串库:对于正则表达式等高级需求,请考虑使用 Quicklisp 中的库,Quicklisp 是 Common Lisp 的事实标准包管理器 (package manager)。一个流行的选择是
cl-ppcre。