Perl6中的语法有点太贪心了

jjm*_*elo 7 regex grammar perl6 regex-greedy

我遇到了这个迷你语法的问题,它试图匹配像markdown一样的头部结构.

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+ <span> [\h* $0]? $$}
}
Run Code Online (Sandbox Code Playgroud)

我希望它匹配## Easier ##为标题,但它##作为一部分span:

TOP
|  header
|  |  hashes
|  |  * MATCH "##"
|  |  span
|  |  |  like-a-word
|  |  |  * MATCH "Easier"
|  |  |  like-a-word
|  |  |  * MATCH "##"
|  |  |  like-a-word
|  |  |  * FAIL
|  |  * MATCH "Easier ##"
|  * MATCH "## Easier ##"
* MATCH "## Easier ##\n"
?## Easier ##
?
 header => ?## Easier ##?
  hashes => ?##?
  span => ?Easier ##?
   like-a-word => ?Easier?
   like-a-word => ?##?
Run Code Online (Sandbox Code Playgroud)

问题是,[\h* $0]?只是span吞噬了所有可用的单词,似乎根本不起作用.任何的想法?

mor*_*itz 5

首先,正如其他人所指出的那样,<hashes>它不会被捕获$0,而是被捕获$<hashes>,所以你必须写:

regex header {^^ <hashes> \h+ <span> [\h* $<hashes>]? $$}
Run Code Online (Sandbox Code Playgroud)

但这仍然与你想要的方式不符,因为该[\h* $<hashes>]?部分很乐意匹配零次出现.

正确的解决方法是不要将span匹配##作为一个单词:

role Like-a-word {
    regex like-a-word { <!before '#'> \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+ <span> [\h* $<hashes>]? $$}
}

say Grammar::Headers.subparse("## Easier ##\n", :rule<header>);
Run Code Online (Sandbox Code Playgroud)

如果你不愿意修改like-a-word,你也可以强制#从中排除决赛:

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+ <span> <!after '#'> [\h* $<hashes>]? $$}
}

say Grammar::Headers.subparse("## Easier ##\n", :rule<header>);
Run Code Online (Sandbox Code Playgroud)

  • @jjmerelo思考/测试的食物:`##左边两个哈希,三个右边###`; 和##两个哈希左边,两个加两个右边## ##`; 和##左边两个哈希,右边两个加三个## ###`; 和##两个哈希左边,三个加两个右边### ##`; 和## ##左边两个加两个哈希,右边两个加两个哈希## ##`; 和##两个哈希左边,两个加两个右边## ##`; 和##两个哈希左边,两个在中间##和一些更多文本##`;? (2认同)
  • @jjmerelo你总是可以尝试先进行更严格的解析,然后使用`||`回退到总是匹配的东西. (2认同)