LISP - 字符串修剪
现代 Lisp:字符串修剪
Section titled “现代 Lisp:字符串修剪”在 Common Lisp 中,从字符串的开头或结尾删除不需要的字符——这一过程被称为修剪(trimming)——是一项常见且直接的任务。该语言提供了一套强大、内置的函数,专为此目的设计。本更新教程将探讨这些函数、它们的现代用法和最佳实践。
标准字符串修剪函数
Section titled “标准字符串修剪函数”Common Lisp 中字符串修剪的核心围绕三个主要函数展开。它们都通过将字符串中的字符与一个字符袋(即一个包含要删除字符的序列)进行比较来工作。
| 函数 | 描述 |
|---|---|
string-trim | 接受一个字符袋和一个字符串。它返回一个新字符串,其中包含已从字符串的开头和结尾移除字符袋中所有字符。 |
string-left-trim | 类似于 string-trim,但只从字符串的开头(左侧)移除字符。 |
string-right-trim | 类似于 string-trim,但只从字符串的结尾(右侧)移除字符。 |
什么是字符袋?
Section titled “什么是字符袋?”这些函数的第一个参数是一个字符序列,我们称之为“字符袋”。它不是要匹配的子字符串。相反,字符袋中存在的任何字符都将从目标字符串的两端被修剪掉。字符袋中字符的顺序无关紧要。
例如,如果字符袋是 "ab ",这些函数将从字符串两端修剪掉任何 ‘a’、‘b’ 或空格字符。
示例:使用内置修剪函数
Section titled “示例:使用内置修剪函数”让我们看看这些函数的实际应用。以下代码演示了如何从字符串中修剪空格和其他字符。我们使用 format 进行输出,这是在 Lisp 中打印文本的一种高度灵活且符合语言习惯的方式。
(defun run-trimming-examples () "演示标准字符串修剪函数。" (let ((my-string " a big hello from tutorials point ") (whitespace-bag '(#\Space #\Tab #\Newline)))
(format t "Original: '~a'~%~%" my-string)
;; 从两端修剪空格 (format t "string-trim: '~a'~%" (string-trim whitespace-bag my-string))
;; 只从左侧修剪空格 (format t "string-left-trim: '~a'~%" (string-left-trim whitespace-bag my-string))
;; 只从右侧修剪空格 (format t "string-right-trim: '~a'~%" (string-right-trim whitespace-bag my-string))
;; 使用不同字符袋的示例 (let ((another-string "...!!hello world!!...") (punctuation-bag ".!")) (format t "~%Trimming punctuation: '~a'~%" (string-trim punctuation-bag another-string)))))
;; 运行示例(run-trimming-examples)Original: ' a big hello from tutorials point '
string-trim: 'a big hello from tutorials point'string-left-trim: 'a big hello from tutorials point 'string-right-trim: ' a big hello from tutorials point'
Trimming punctuation: 'hello world'进阶主题:一个自定义修剪函数
Section titled “进阶主题:一个自定义修剪函数”虽然内置函数通常足够使用,但您可能偶尔需要根据条件而不是固定的字符集进行修剪。例如,您可能想要从字符串中修剪掉所有数字。这需要一个使用谓词的自定义函数。
下面是一个结构良好的自定义 trim-if 函数。请注意,它使用 position-if-not 来查找第一个不应该被修剪的字符。
(defun trim-if (predicate string) "修剪字符串 STRING 两端,使 PREDICATE 返回 true 的字符。 示例:(trim-if #'digit-char-p \"123hello456\") => \"hello\"" (let* ((start (position-if-not predicate string)) (end (position-if-not predicate string :from-end t))) (if start (subseq string start (and end (1+ end))) "")))
;; --- 示例用法 ---
;; 修剪所有数字字符(format t "Custom trim (digits): '~a'~%" (trim-if #'digit-char-p "123abc456"))
;; 修剪所有非字母字符(format t "Custom trim (non-letters): '~a'~%" (trim-if (lambda (c) (not (alpha-char-p c))) "--hello world!--"))Custom trim (digits): 'abc'Custom trim (non-letters): 'hello world'最佳实践和常见陷阱
Section titled “最佳实践和常见陷阱”- 优先使用内置函数:尽可能始终使用标准的
string-trim、string-left-trim和string-right-trim。它们经过高度优化,并且是标准的一部分,使您的代码可移植且易读。 - 字符袋与子字符串的区别:一个常见的错误是认为
(string-trim "abc" "abcdef")会移除前缀 “abc”。它不会。它会移除两端所有 ‘a’、‘b’ 或 ‘c’ 字符。在这种情况下,结果是"def"。 - 性能:对于性能关键的代码,请记住这些函数会创建一个新字符串。在紧密循环中进行修剪可能会导致内存分配开销。如果性能是一个问题,请考虑替代的数据处理策略。