如何在 Perl 6 中将 sub 放入正则表达式中?

How to put a sub inside a regex in Perl 6?

这就是我想要做的。

>  my sub nplus1($n) {$n +1}
> my regex nnplus1 { ^ (\d+) &nplus1([=10=]) $ }
> "123" ~~ &nnplus1
P6opaque: no such attribute '$!pos' in type Match...

请记住,正则表达式是子句。所以不要称你的匹配器为 sub——更具体一点,称其为 regex。是的,您可以将参数传递给 regex/token/rule。当您匹配在解析时更改其状态的语言时,执行此操作非常重要。例如,在 YAML 中,您可以解析 "data[0]: 17"。之后,下一行可以以 "data[1]" 开头,但不能以 "data[2]" 开头。因此,将额外信息作为参数传递是很有用的。

另请注意,当您将其转换为正则表达式时,某些情况会发生变化。 $n+1 将具有新的含义(这是错误的)。但是,简单变量仍然是内插的,因此如果您在正则表达式主体中使用 :my $npp = ... 将其声明为新变量。但即便如此,你会发现它仍然不起作用。当您添加像 {say "n is $n"} 这样的辅助语句时,您会发现没有传递有效参数。这是因为在没有大括号的类似代码的上下文中(当您使用表达式作为另一个匹配器的参数时),rakudo 不会更新匹配变量。添加大括号时,将重新计算或重新缓存当前匹配变量。这个 hack 看起来像是打字错误,所以我建议您添加一条注释来解释空括号。最终代码是这样的:

my regex nplus1($n) {
 :my $npp=$n+1;
 $npp
}
my regex nnplus1 { (\d+) {} <nplus1([=10=])> }
say "123124" ~~ &nnplus1;

在这种情况下(基本上是递归),我喜欢通过更改参数中的数据而不是更改函数主体中的数据来使事情更整洁:<nplus1([=19=]+1)> 而不是定义 :my $npp = $n+1;

根据 Regex interpolation docs as well as on 和 Håkon Hægland 的评论,我似乎已经做到了我想做的事情:

my sub nplus1($n) {
 $n+1;
}
my regex nnplus1 { (\d+) {} <nplus1=$(nplus1([=10=]))> }
say "123124" ~~ &nnplus1;

输出:

「123124」
 0 => 「123」
 nplus1 => 「124」

或者我们可以移动 {} 来包含内插子:

my sub nplus1($n) {
 $n+1;
}
my regex nnplus1 { (\d+)  <nplus1={nplus1([=12=])}> }
say "123124" ~~ &nnplus1;

(输出相同)

<{...}> 构造在正则表达式中运行 Perl 6 代码,并将结果计算为正则表达式:

my sub nplus1($n) {$n +1} my regex nnplus1 { ^ (\d+) <{ nplus1([=11=]) }> $ } say so '23' ~~ &nnplus1; # Output: True say so '22' ~~ &nnplus1; # Output: False