我想语法做这样的事情:
> "abc" ~~ m:ex/^ (\w ** 1..2) (\w ** 1..2) ${say $0,$1}/ 「ab」「c」 「a」「bc」
或者像这样:
> my regex left { \S ** 1..2 } > my regex right { \S ** 1..2 } > "abc" ~~ m:ex/^ <left><right> ${say $<left>,$<right>}/ 「ab」「c」 「a」「bc」
这是我的语法:
grammar LR { regex TOP { <left> <right> } regex left { \w ** 1..2 } regex right { \w ** 1..2 } } my $string = "abc"; my $match = LR.parse($string); say "input: $string"; printf "split: %s|%s\n",~$match<left>,~$match<right>;
它的输出是:
$input: abc $split: ab|c
所以,< left>可能只是贪婪而没有任何东西给< right>.我应该如何修改代码以匹配两种可能的变体?
$input: abc $split: a|bc,ab|c
解决方法
语法被设计为给出零或一个答案,而不是更多,因此你必须使用一些技巧使它们做你想要的.
由于Grammar.parse只返回一个Match对象,因此您必须使用不同的方法来获取所有匹配项:
sub callback($match) { say $match; } grammar LR { regex TOP { <left> <right> $ { callback($/) } # make the match fail,thus forcing backtracking: <!> } regex left { \w ** 1..2 } regex right { \w ** 1..2 } } LR.parse('abc');
通过调用<!>使匹配失败断言(总是失败)迫使先前的原子回溯,从而找到不同的解决方案.当然,这使得语法不再可重用,因为它在语法的常规调用约定之外工作.
请注意,对于调用者,LR.parse似乎总是失败;你得到所有匹配作为回调函数的调用.
一个稍微好一点的API(但下面的方法相同)是使用gather / take来获取所有匹配的序列:
grammar LR { regex TOP { <left> <right> $ { take $/ } # make the match fail,thus forcing backtracking: <!> } regex left { \w ** 1..2 } regex right { \w ** 1..2 } } .say for gather LR.parse('abc');