You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CL-PPCRE中单行模式与多行模式切换及行为疑问

CL-PPCRE单行模式与多行模式的理解问题及解决

我找不到类似问题的相关信息,搞不懂CL-PPCRE里单行模式(SINGLE-LINE-MODE)和多行模式(MULTI-LINE-MODE)的切换逻辑。试过嵌入修饰符和关键字参数两种方式,但结果都和预期不符。编辑:问题已解决,核心原因是示例字符串错误。


原始请求及测试代码(含两处编辑)

;; 参考Perl教程示例
;; 四种组合示例:
;; $x = "There once was a girl\nWho programmed in Perl\n";
;; $x =~ /^Who/;   # 不匹配,"Who"不在字符串开头
;; $x =~ /^Who/s;  # 不匹配,"Who"不在字符串开头
;; $x =~ /^Who/m;  # 匹配,"Who"在第二行开头
;; $x =~ /^Who/sm; # 匹配,"Who"在第二行开头
;; $x =~ /girl.Who/;   # 不匹配,"."不匹配"\n"
;; $x =~ /girl.Who/s;  # 匹配,"."匹配"\n"
;; $x =~ /girl.Who/m;  # 不匹配,"."不匹配"\n"
;; $x =~ /girl.Who/sm; # 匹配,"."匹配"\n"

;; <<<<<<<<<<<<编辑:这是核心问题所在>>>>>>>>>>>>>
(defparameter *x* "There once was a lady\nWho programmed in Lisp.\n")

;; 后来在#commonlisp频道有人指出,我直接复制了Perl的字符串:
;; "There once was a girl\nWho programmed in Perl.\n"
;; 我当时太专注正则表达式,完全没注意目标字符串的问题。(第一次修改时还写成了:
;; "哦对,你说得对:
;; 'There once was a lady\\nWho programmend in Lisp.\\n'."
;; 真是犯傻了。)
;; 正确的写法应该是这样:
;; -----------------------------------------------------
;; (defparameter *x* (str:concat "There once was a lady"
;;                               (string #\Newline)
;;                               "Who programmed in Lisp."
;;                               (string #\Newline)))
;; ------------------------------------------------------

;; <<<<<<编辑:第二个问题是修饰符位置错误>>>>>>
;; 之前把修饰符放在前面时触发过错误,但显然当时我眼花了……
(ppcre:scan "^Who" *x*)         ; => NIL
(ppcre:scan "^(?s)Who" *x*)     ; => NIL
(ppcre:scan "^(?m)Who" *x*)     ; => NIL —— 遗憾的是和教程结果不同
(ppcre:scan "^(?sm)Who" *x*)    ; => NIL —— 同样不匹配
(ppcre:scan "lady.Who" *x*)     ; => 17, 25, #(), #() —— 匹配成功
(ppcre:scan "(?s)lady.Who" *x*) ; => 17, 25, #(), #() —— 同样匹配
(ppcre:scan "(?m)lady.Who" *x*) ; => 17, 25, #(), #() —— 同样匹配
(ppcre:scan "^(?sm)Who" *x*)    ; => NIL —— 还是不匹配

;; 会不会是修饰符嵌入的位置不对?
(let ((s (ppcre:create-scanner "^Who")))
  (ppcre:scan s *x*)) ; => NIL
(let ((s (ppcre:create-scanner "^Who" :single-line-mode t)))
  (ppcre:scan s *x*)) ; => NIL
(let ((s (ppcre:create-scanner "^Who" :single-line-mode t)))
  (ppcre:scan s *x*)) ; => NIL —— 依然不行
(let ((s (ppcre:create-scanner "lady.Who" :single-line-mode t
                                          :multi-line-mode t)))
  (ppcre:scan s *x*)) ; => 17, 25, #(), #() —— 至少结果一致
(let ((s (ppcre:create-scanner "lady.Who" :single-line-mode t)))
  (ppcre:scan s *x*)) ; => 17, 25, #(), #() —— 同样匹配
(let ((s (ppcre:create-scanner "lady.Who" :multi-line-mode t)))
  (ppcre:scan s *x*)) ; => 17, 25, #(), #() —— 同样匹配
(let ((s (ppcre:create-scanner "^Who" :single-line-mode t
                                      :multi-line-mode t)))
  (ppcre:scan s *x*)) ; => NIL —— 还是不匹配

理解障碍的测试用例

;; 三个let表达式分别输出结果:
(let ((s (ppcre:create-scanner "^.$" :multi-line-mode nil)))
  (ppcre:scan s "\\n"))                              ; => NIL —— 和上面结果一致
(let ((s (ppcre:create-scanner "^.$" :multi-line-mode nil)))
  (ppcre:scan s "a"))                     ; => 0, 1, #(), #() —— 和上面结果一致
(let ((s (ppcre:create-scanner "^.$" :multi-line-mode nil)))
  (ppcre:scan s "a\\n"))                             ; => NIL —— 和上面结果一致

;; 这看起来是默认设置。现在试试相反的配置:

(let ((s (ppcre:create-scanner "^.$" :multi-line-mode t)))
  (ppcre:scan s "\\n"))                              ; => NIL —— 和上面结果一致
(let ((s (ppcre:create-scanner "^.$" :multi-line-mode t)))
  (ppcre:scan s "a"))                     ; => 0, 1, #(), #() —— 和上面结果一致
(let ((s (ppcre:create-scanner "^.$" :multi-line-mode t)))
  (ppcre:scan s "a\\n"))                             ; => NIL —— 和上面结果一致

;; 奇怪了。

;; 文档说明:
;; "* 如果适合你的任务,可以考虑使用'单行模式'。
;;   默认情况下(遵循Perl惯例),点号匹配除换行符外的任意字符。
;;   在单行模式下,点号匹配任意字符,某些情况下可以跳过目标字符串的大部分内容,
;;   处理大目标时效率会高很多。"

;; 那默认情况下:MULTI-LINE-MODE应该是T?但为什么没效果?

(let ((s (ppcre:create-scanner "^.$" :multi-line-mode nil :single-line-mode t)))
  (ppcre:scan s "\\n"))                              ; => NIL —— 和上面结果一致
(let ((s (ppcre:create-scanner "^.$" :multi-line-mode nil :single-line-mode t)))
  (ppcre:scan s "a"))                     ; => 0, 1, #(), #() —— 和上面结果一致
(let ((s (ppcre:create-scanner "^.$" :multi-line-mode nil :single-line-mode t)))
  (ppcre:scan s "a\\n"))                             ; => NIL —— 和上面结果一致

内容的提问来源于stack exchange,提问作者Demihm Seinname

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 04:54:52