LISP - 获取子字符串
Lisp - 字符串操作和子字符串
Section titled “Lisp - 字符串操作和子字符串”在 Common Lisp 中,字符串是专门的一维字符数组。由于字符串是序列,因此许多强大的序列函数可用于操作它们。提取字符串一部分最基本的操作是创建子字符串。
使用 subseq 提取子字符串
Section titled “使用 subseq 提取子字符串”subseq 函数(sub-sequence 的缩写,即“子序列”)是提取任何序列(包括字符串)一部分的主要工具。其语法是 (subseq sequence start &optional end)。
sequence:要从中提取的字符串(或其他序列)。start:子字符串的基于 0 的起始索引(包含)。end:可选的基于 0 的结束索引(不包含)。如果省略,子字符串将延伸到字符串的末尾。
示例:基本子字符串提取
Section titled “示例:基本子字符串提取”(defparameter *message* "Welcome to the Lisp world!")
;; 获取从索引 15 到末尾的子字符串(format t "Substring (end): '~a'~%" (subseq *message* 15))
;; 获取从索引 8 到 14 的子字符串(format t "Substring (range): '~a'~%" (subseq *message* 8 14))Substring (end): 'Lisp world!'Substring (range): 'to the'使用无效索引调用 subseq 会引发错误。验证索引或优雅地处理潜在错误是良好的实践,例如,通过使用 handler-case。
示例:处理无效索引
Section titled “示例:处理无效索引”(defun safe-subseq (str start &optional end) "一个安全的 subseq 包装器,在出错时返回 NIL。" (handler-case (subseq str start end) ;; 在 Common Lisp 中,所有错误都继承自 `error` 条件。 (error (c) (format t "Error while getting substring: ~a~%" c) nil)))
;; --- 用法 ---
;; 这将失败,因为起始索引超出范围(let ((result (safe-subseq "Hello" 10))) (format t "Result of invalid call: ~a~%" result))
;; 这将失败,因为结束索引超出范围(let ((result (safe-subseq "Hello" 0 100))) (format t "Result of invalid call: ~a~%" result))Error while getting substring: The start bounding index, 10, is beyond the end of the sequence, 5.Result of invalid call: NILError while getting substring: The end bounding index, 100, is beyond the end of the sequence, 5.Result of invalid call: NILhandler-case 宏尝试执行其第一个表单。如果在执行期间引发 error 条件,它会捕获条件对象 c,打印一条消息,并返回 nil 而不是使程序崩溃。
实际应用:解析日志条目
Section titled “实际应用:解析日志条目”子字符串对于解析结构化文本至关重要。让我们编写一个函数来将类似 "[INFO] 2023-10-27: User logged in." 的日志条目解析成其组成部分。
(defun parse-log-entry (log-line) "解析日志条目并将其组件作为列表返回。" (let* ((level-end (position #] log-line)) (date-start (+ level-end 2)) (date-end (+ date-start 10)) (msg-start (+ date-end 2))) (list :level (subseq log-line 1 level-end) :date (subseq log-line date-start date-end) :message (subseq log-line msg-start))))
;; --- 用法 ---(defparameter *log1* "[INFO] 2023-10-27: User logged in.")(defparameter *log2* "[ERROR] 2023-10-28: Database connection failed.")
(print (parse-log-entry *log1*))(print (parse-log-entry *log2*))(:LEVEL "INFO" :DATE "2023-10-27" :MESSAGE "User logged in.")(:LEVEL "ERROR" :DATE "2023-10-28" :MESSAGE "Database connection failed.")其他有用的字符串函数
Section titled “其他有用的字符串函数”除了 subseq 之外,Lisp 标准库还包括许多其他有用的字符串操作函数:
- 搜索:
(search "needle" "haystack")查找子字符串的起始位置。 - 拼接:
(concatenate 'string "Hello, " "world!")将多个字符串连接在一起。 - 修剪:
(string-trim '(#\Space #\Tab) " some text ")从字符串两端移除空白字符。 - 大小写转换:
string-upcase、string-downcase和string-capitalize用于改变字符串的大小写。