更正正则表达式“\[([a-zA-Z0-9_-]+)]”

Correcting the regex "\[([a-zA-Z0-9_-]+)]"

以下 cl-ppcre 正则表达式生成错误:

(ppcre:scan-to-strings "\[([a-zA-Z0-9_-]+)]" "[has-instance]")

debugger invoked on a CL-PPCRE:PPCRE-SYNTAX-ERROR in thread
#<THREAD "main thread" RUNNING {10010B0523}>:
  Expected end of string. at position 16 in string "[([a-zA-Z0-9_-]+)]"

我期望的 return 值是:

“[has-instance]”
#(“has-instance”)

为了得到括号内的字符串。有人可以提供正则表达式更正吗?谢谢

转义符(反斜杠)只转义自身和双引号(§2.4.5 Double-Quote):

If a single escape character is seen, the single escape character is discarded, the next character is accumulated, and accumulation continues.

这意味着:

 "\[([a-zA-Z0-9_-]+)]" 

被解析为与以下相同,其中不存在反斜杠:

 "[([a-zA-Z0-9_-]+)]"

CL-PPCRE 实现的 PCRE 语法将左方括号理解为字符 classes 的特殊语法,并在下一个右括号处结束。 因此,上面的内容是 class:

[([a-zA-Z0-9_-]

对应的正则表达式树为:

CL-USER> (ppcre:parse-string "[([a-zA-Z0-9_-]")
(:CHAR-CLASS #\( #\[ (:RANGE #\a #\z) (:RANGE #\A #\Z) (:RANGE #[=13=] #) #\_ #\-)

特别注意里面的左括号是按字面意思对待的。当解析器遇到上述片段后的右括号时,它将其解释为寄存器组的结尾,但没有启动这样的组,因此在字符串的第 16 位出现错误消息。

为避免将括号视为字符 class,它必须在字符串中以文字反斜杠开头,正如您尝试做的那样,但为了这样做,您必须 写入两个反斜杠字符:

CL-USER> (ppcre:parse-string "\[([a-zA-Z0-9_-]+)]")
(:SEQUENCE #\[
 (:REGISTER
  (:GREEDY-REPETITION 1 NIL
   (:CHAR-CLASS (:RANGE #\a #\z) (:RANGE #\A #\Z) (:RANGE #[=14=] #) #\_ #\-)))
 #\])

右方括号不需要反斜杠。

我鼓励您使用树形形式在 Lisp 中编写正则表达式,并在提高清晰度时使用 :regex 项:它避免了必须处理转义带来的那种问题。例如:

CL-USER> (ppcre:scan-to-strings 
           '(:sequence "[" (:register (:regex "[a-zA-Z0-9_-]+")) "]")
           "[has-instance]")
"[has-instance]"
#("has-instance")
  1. 两次转义方括号。
  2. 你也忘了 (double) 转义右括号。
(cl-ppcre:scan-to-strings "\[([a-zA-Z0-9_-]+)\]" "[has-instance]")
;; "[has-instance]" ;
;; #("has-instance")

对于 common lisp 的新手,您可以使用 quicklisp 导入 cl-ppcre

(load "~/quicklisp/setup.list") ;; adjust path to where you installed your quicklisp
(ql:quickload :cl-ppcre)