CLisp 27:处理正则表达式regexp

来源:互联网 发布:艾欧尼亚30级账号淘宝 编辑:程序博客网 时间:2024/06/03 10:32

       有很多处理正则表达式的组件,这里介绍Common LISP安装包自带的package regexp。不同组件的实现方式略有不同,对正则表达式的支持程度不同,但对外接口是相似的,可以举一反三。

       直接匹配正则表达式的接口:(regexp:match pattern string ...)

       先编译后匹配的接口:(regexp:regexp-compile pattern ...) (regexp:regexp-exec compiled-pattern string ...)

       匹配操作返回的结果为结构体regexp:match,操作此结构体的接口:(regexp:match-start match)(regexp-match-end match)  (regexp:match-string string match)

       对特殊字符进行转义的接口,配合match可以实现纯粹的字符串搜索功能:(regexp:regexp-quote string ...)

       分割字符串的接口:(regexp:regexp-split pattern string ...) (regexp:with-loop-split ...)

      

       匹配操作只返回第一个匹配的位置,如果要找出所有匹配,可以将上次匹配的末尾作为下次匹配的开始。例如找出字符串中所有的整数:

(defun foo (str)

(let ((s 0))

    (loop :with compiled = (regexp:regexp-compile "[0-9][0-9]*")

     :for m = (regexp:regexp-exec compiled str :start s)

     :while m

     :collect (if m

                (regexp:match-string str m))

     :do (setq s (regexp:match-end m)))))

(foo "123 is 123, 321 is 321!")

 

       再看一个解析IP地址的例子,从字符串形式的IP地址中取出四个整数。

(defun ip-to-num (ip)

  (multiple-value-bind (ip0 ip1 ip2 ip3 ip4)

   (regexp:match "\\([0-9]*\\)\\.\\([0-9]*\\)\\.\\([0-9]*\\)\\.\\([0-9]*\\)" ip)

   (if ip4

       (mapcar #'(lambda (m) (parse-integer (regexp:match-string ip m)))

              (list ip1 ip2 ip3 ip4)))))

(ip-to-num “127.0.0.1”)输出 (127 0 0 1)

       正则表达式中有 \\( XXX \\)格式,注意两边的括号,它匹配的字符串和 XXX 是一样的,但返回的结果中会返回这个子串的起始、结束地址。例如,执行上面例子中的regexp:match语句,返回下面结果。multiple-value-bind用来接收返回的多个值。

#S(REGEXP:MATCH :START 0 :END 9) ;  整个匹配上的字符串

#S(REGEXP:MATCH :START 0 :END 3) ;第一对括号对应的字串

#S(REGEXP:MATCH :START 4 :END 5) ;第二对括号对应的字串

#S(REGEXP:MATCH :START 6 :END 7) ;第三对括号对应的字串

#S(REGEXP:MATCH :START 8 :END 9) 第四对括号对应的字串