Perl6语法匹配Markdown标题时贪婪匹配问题求助
这个问题的核心在于你的span正则是贪婪匹配的,它会把所有符合<like-a-word>规则的内容(包括末尾的##)都吞掉,导致后面的[\h* $0]?完全没有机会触发匹配——毕竟##是\S+,完美符合<like-a-word>的定义。
要解决这个问题,我们需要让span在遇到行尾的闭合哈希序列时停下来,也就是让它匹配到可选的闭合哈希之前的内容。这里有两种比较优雅的调整方式:
方法一:利用动态变量+先行断言限制span的匹配范围
我们可以在header里把开头捕获到的哈希序列存在动态变量中,然后让span的正则通过先行断言,确保它不会把行尾的闭合哈希包含进去:
role Like-a-word { regex like-a-word { \S+ } } role Span does Like-a-word { regex span { <like-a-word> [\s+ <like-a-word>]*? # 改成非贪婪匹配,给后面的闭合哈希留机会 <!before \h* $*HASHES $$> # 断言当前位置后不是行尾的闭合哈希 } } grammar Grammar::Headers does Span { token TOP {^ <header> \v+ $} token hashes { '#'**1..6 } regex header { ^^ <hashes> { $*HASHES = $<hashes> } # 把开头的哈希序列存到动态变量里 \h+ <span> [\h* $0]? # 现在这个部分就能正常匹配末尾的闭合哈希了 $$ } }
方法二:直接重构header的正则结构
如果不想用动态变量,也可以直接在header里调整匹配顺序,用非贪婪匹配捕获标题内容,再让闭合哈希的匹配优先:
role Like-a-word { regex like-a-word { \S+ } } role Span does Like-a-word { regex span { <like-a-word>[\s+ <like-a-word>]* } } grammar Grammar::Headers does Span { token TOP {^ <header> \v+ $} token hashes { '#'**1..6 } regex header { ^^ <hashes> \h+ ( <like-a-word> ( \s+ <like-a-word> )*? ) # 非贪婪匹配标题内容 ( \h* $0 )? # 优先匹配闭合哈希 $$ { make $0 => $1 } # 可选:把结果整理成更清晰的结构 } }
测试效果
现在再匹配## Easier ##,你会看到:
hashes捕获到开头的##span(或第二个捕获组)捕获到Easier- 末尾的
##会被[\h* $0]?正确捕获,而不是被span吃掉
这样就完美符合Markdown标题的匹配规则了。
内容的提问来源于stack exchange,提问作者jjmerelo
相关产品推荐
相关产品推荐

