如何使 Perl 6 语法产生多个匹配项(如 :ex 和 :ov)?
How to make Perl 6 grammar produce more than one match (like :ex and :ov)?
我想grammar
做这样的事情:
> "abc" ~~ m:ex/^ (\w ** 1..2) (\w ** 1..2) $ {say [=10=], }/
「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
:
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
我认为 Moritz Lenz,昵称 moritz,即将出版的新书 "Parsing with Perl 6 Regexes and Grammars" 的作者是问这个问题的人。我可能应该让他回答这个问题……
备注
如果有人考虑尝试修改 grammar.parse
以使其支持 :exhaustive
,或者以其他方式进行黑客攻击以执行@evb 想要的操作,以下文档可能有用 inspiration/guidance 我从相关的推测文档 (S05) 和搜索 #perl6 和 #perl6-dev irc 日志中收集。
7 年前 莫里茨补充道 an edit of S05:
A [regex] modifier that affects only the calling behaviour, and not the regex itself [eg :exhaustive
] may only appear on constructs that involve a call (like m//
[or grammar.parse
]), and not on rx//
[or regex { ... }
].
([例如 :exhaustive
]、[或 grammar.parse
] 和 [或 regex { ... }
] 位是 extrapolations/interpretations/speculations 我在这个 SO 答案中添加的。它们不在链接源中。)
5年前莫里茨expressed interest in implementing :exhaustive
for matching (not parsing) features. Less than 2 minutes later jnthn showed a one liner that demo'd how he guessed he'd approach it. Less than 30 minutes later Moritz posted a working prototype. The final version landed 7 days later.
1 年前Moritz 在#perl6 上说(强调 由我添加):"regexes and grammars aren't a good tool to find all possible ways to parse a string".
Hth.
Grammars are designed给出零个或一个答案,不能超过,所以你必须使用一些技巧让他们做你想做的事情。
由于 Grammar.parse
returns 只有一个 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');
我想grammar
做这样的事情:
> "abc" ~~ m:ex/^ (\w ** 1..2) (\w ** 1..2) $ {say [=10=], }/
「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
:
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
我认为 Moritz Lenz,昵称 moritz,即将出版的新书 "Parsing with Perl 6 Regexes and Grammars" 的作者是问这个问题的人。我可能应该让他回答这个问题……
备注
如果有人考虑尝试修改 grammar.parse
以使其支持 :exhaustive
,或者以其他方式进行黑客攻击以执行@evb 想要的操作,以下文档可能有用 inspiration/guidance 我从相关的推测文档 (S05) 和搜索 #perl6 和 #perl6-dev irc 日志中收集。
7 年前 莫里茨补充道 an edit of S05:
A [regex] modifier that affects only the calling behaviour, and not the regex itself [eg
:exhaustive
] may only appear on constructs that involve a call (likem//
[orgrammar.parse
]), and not onrx//
[orregex { ... }
].
([例如 :exhaustive
]、[或 grammar.parse
] 和 [或 regex { ... }
] 位是 extrapolations/interpretations/speculations 我在这个 SO 答案中添加的。它们不在链接源中。)
5年前莫里茨expressed interest in implementing :exhaustive
for matching (not parsing) features. Less than 2 minutes later jnthn showed a one liner that demo'd how he guessed he'd approach it. Less than 30 minutes later Moritz posted a working prototype. The final version landed 7 days later.
1 年前Moritz 在#perl6 上说(强调 由我添加):"regexes and grammars aren't a good tool to find all possible ways to parse a string".
Hth.
Grammars are designed给出零个或一个答案,不能超过,所以你必须使用一些技巧让他们做你想做的事情。
由于 Grammar.parse
returns 只有一个 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');