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
相关产品推荐
相关产品推荐

