2

以下 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_-]+)]"

我期望的返回值是:

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

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

4

2 回答 2

4

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

如果看到单个转义字符,则丢弃单个转义字符,累积下一个字符,并继续累积。

这意味着:

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

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

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

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

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

对应的正则表达式树是:

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

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

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

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

右方括号不需要反斜杠。

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

CL-USER> (ppcre:scan-to-strings 
           '(:sequence "[" (:register (:regex "[a-zA-Z0-9_-]+")) "]")
           "[has-instance]")
"[has-instance]"
#("has-instance")
于 2020-04-29T23:02:43.020 回答
0
  1. 双重转义方括号。
  2. 您也忘记(双重)转义右括号。
(cl-ppcre:scan-to-strings "\\[([a-zA-Z0-9_-]+)\\]" "[has-instance]")
;; "[has-instance]" ;
;; #("has-instance")

对于那些不熟悉 common lisp 的人,您可以cl-ppcre使用 quicklisp 进行导入:

(load "~/quicklisp/setup.list") ;; adjust path to where you installed your quicklisp
(ql:quickload :cl-ppcre)
于 2020-04-30T07:55:51.797 回答