将行尾与CL-PPCRE相匹配

时间:2018-12-27 05:01:40

标签: regex common-lisp cl-ppcre

我有一个相当简单的正则表达式,可以在我的Ruby代码中很好地工作,但是拒绝在我的Lisp代码中工作。我只是想匹配一个URL(斜杠后跟一个单词,仅此而已)。这是我在Ruby中可以使用的正则表达式:^\/\w*$

我希望它匹配"/""/foo",但不匹配"/foo/bar"

我尝试了以下操作:

(cl-ppcre:scan "^/\w*$" "/") ;works
(cl-ppcre:scan "^/\w*$" "/foo") ;doesn't work!
(cl-ppcre:scan "^/\w*$" "/foo/bar") ;works, ie doesn't match

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:8)

默认情况下,反斜杠(\)字符是single escape character:它可以防止对后面的字符进行任何特殊处理,因此可以使用双引号({{1} })这样的字符串文字"中。

因此,当您将文字字符串"\""传递给"^/\w*$"时,传递的实际字符串将是cl-ppcre:scan,即反斜杠将被删除。您可以通过评估匹配的"^/w*$"来验证这一点。

要将正斜杠字符包含在正则表达式中,您需要像这样引用它:(cl-ppcre:scan "^/\w*$" "/w")

如果您经常使用文字正则表达式,则所需的字符串引号可能会变得乏味且难以阅读。看看CL-INTERPOL的库,它为Lisp阅读器添加了更好的正则表达式语法。

答案 1 :(得分:3)

如果对正则表达式有疑问,也可以使用ppcre:parse-string进行检查:

CL-USER> (ppcre:parse-string "^/\w*$")
(:SEQUENCE :START-ANCHOR #\/ (:GREEDY-REPETITION 0 NIL #\w) :END-ANCHOR)

以上内容告诉我们,反斜杠-w被解释为文字w字符。

将此与您要使用的表达式进行比较:

CL-USER> (ppcre:parse-string "^/\\w*$")
(:SEQUENCE :START-ANCHOR #\/ (:GREEDY-REPETITION 0 NIL :WORD-CHAR-CLASS) :END-ANCHOR)

返回的值是代表正则表达式的树。实际上,您可以在CL-PPCRE需要正则表达式的任何地方使用相同的表示形式。即使有些冗长,这也有助于将值合并到正则表达式中,而不必担心在字符串中嵌套字符串或特殊字符:

(defun maybe (regex)
  `(:greedy-repetition 0 1 ,regex))

(defparameter *simple-floats*
  (let ((digits '(:register (:greedy-repetition 1 nil :digit-class))))
    (ppcre:create-scanner `(:sequence
                             (:register (:regex "[+-]?"))
                             ,digits
                             ,(maybe `(:sequence "." ,digits))))))

在上面,点"."是按字面意义而不是正则表达式。这意味着您可以匹配诸如"(^.^)""[]"之类的字符串,这些字符串可能很难用纯字符串正则表达式中的转义字符编写和读取。您可以使用(:regex "...")表达式退回到字符串形式的正则表达式。

CL-PPCRE进行了优化,在加载时使用load-time-value预计算了常量正则表达式。如果您的正则表达式不是平凡的常量,则可能不会应用该优化,因此您可能希望将自己的扫描程序包装为load-time-value形式。只需确保在加载时准备好足够的定义即可,例如辅助maybe函数。