ANSI Common Lisp 并不支持正则表达式,但是也有第三方库,如:cl-ppcre

同时也可以到 Cliki:regexp 上了解更多的知识。

注意,有些解释其默认是实现了正则表达式的,尤其是 CLISPALLEGRO CL 具体的可以查阅相关的解释器的文档。

PPCRE

使用 PPCRE 库

CL-PPCRE,全称为 Portable Perl-compatible regular expressions。是个性能比较好的库,可以通过 Quicklisp 来调用:

  1. (ql:quickload :cl-ppcre)
  2. (use-package :cl-ppcre)

寻找匹配项

scan

  1. (let ((ptrn (ppcre:create-scanner "(a)*b")))
  2. (ppcre:scan ptrn "xaaabd"))

等效于

  1. (ppcre:scan "(a)*b" "xaaabd")

但是第一种的方法需要的时间更少,而且只会在编译时对表达式进行解析。

提取信息

CL-PPCRE 有多种提取信息的方法,其中最常用的是:scan-to-stringsregister-groups-bind。其中 scan-to-stringsscan 类似,只不过返回的是匹配到的字符串,而不是位置。
register-groups-bind 可以将匹配到的字符串给绑定到相对应的变量上,如下:

  1. (ppcre:register-groups-bind (first second third fourth)
  2. ("((a)|(b)|(c)+" "abababc" :sharedp t)
  3. (list first second third fourth))
  4. ;; => ("c" "a" "b" "c")

CL-PPCRE 也可以在对匹配的项调用函数,然后再把函数处理后的结果赋给最后的返回结果

  1. (ppcre:register-groups-bind (fname lname (#'parse-integer date month year))
  2. ("(\\w+)\\s+(\\w+)\\s+(\\d{1,2})\\.(\\d{1,2})\\.(\\d{4})" "Frank Zappa 21.12.1940")
  3. (list fname lname (encode-universal-time 0 0 0 date month year 0)))
  4. ;; => ("Frank "Zappa" 1292889600)

语法糖

当 CL-PPCRE 和 CL-INTERPOL 两个库结合使用时效果会更好。CL-INTERPOL 库可以在输入时插入 Perl,Scala 或是 Unix Shell 脚本。
在调用 CL-INTERPOL 之前,需要调用函数 enable-interpol-syntax 先进行初始化:

  1. (interpol:enable-interpol-syntax)

更多关于语法糖的使用,参见 cl21