我有一个相当简单的正则表达式,它在我的 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
有人可以帮忙吗?
反斜杠 (\) 字符默认为 单转义字符:它可以防止对其后面的字符进行任何特殊处理,因此可用于在其中包含双引号 (
"
)像这样的字符串文字 "\""
.
因此,当您将文字字符串
"^/\w*$"
传递给 cl-ppcre:scan
时,传递的实际字符串将是 "^/w*$"
,即反斜杠将被删除。您可以通过评估 (cl-ppcre:scan "^/\w*$" "/w")
来验证这一点,它将匹配。
要在正则表达式中包含反斜杠字符,您需要像这样引用它:
"^/\\w*$"
。
如果您经常使用文字正则表达式,则所需的字符串引用可能会变得乏味且难以阅读。查看 CL-INTERPOL,了解一个为 Lisp 阅读器添加更好的正则表达式语法的库。
如果你对正则表达式有疑问,也可以用
ppcre:parse-string
来检查:
CL-USER> (ppcre:parse-string "^/\w*$")
(:SEQUENCE :START-ANCHOR #\/ (:GREEDY-REPETITION 0 NIL #\w) :END-ANCHOR)
返回值是一棵表示正则表达式的树。事实上,您可以在 CL-PPCRE 需要正则表达式的任何地方使用相同的表示形式。 上面告诉我们反斜杠-
w
被解释为字面的w
字符。
将此与您想要使用的表达式进行比较:
CL-USER> (ppcre:parse-string "^/\\w*$")
(:SEQUENCE
:START-ANCHOR #\/
(:GREEDY-REPETITION 0 NIL :WORD-CHAR-CLASS)
:END-ANCHOR)
尽管它有点冗长,但树表示有助于将值组合到正则表达式中,而不必担心字符串内嵌套字符串或特殊字符。例如,这里正则表达式在使用之前在函数中计算,而不必转义特殊字符:
(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 "...")
表达式将正则表达式作为字符串使用。
load-time-value
预先计算常量正则表达式。如果您的正则表达式不是简单的常量,则可能不会应用该优化,因此您可能希望将自己的扫描器包装在 load-time-value
形式中。只需确保在加载时准备好足够的定义,例如辅助 maybe
函数。