命名正则表达式无法在 raku 中捕获

Named regex fails capture in raku

有人可以解释为什么捕获(命名和未命名)在命名正则表达式中似乎不起作用吗?我是 期待这是我做错的事情,但如果是这样,我看不到。这里被捕获 来自 raku repl 的文本作为我的简短示例。

> my $s = '16.01.2020 09:18 286';
> my $dReg = /^(\d**2)\.(\d**2)\.(\d**4)/;
> $s ~~ /<$dReg>/;
「16.01.2020」
> if $s ~~ /<$dReg>/ { say [=10=] }
Nil
> my $dReg1 = /^$<day> = (\d**2)\.$<mon> = (\d**2)\.$<year> = (\d**4)/;
/^$<day> = (\d**2)\.$<mon> = (\d**2)\.$<year> = (\d**4)/
> $s ~~ /<$dReg1>/;
「16.01.2020」
> if $s ~~ /<$dReg1>/ { say $<day> }
Nil
> if $s ~~ /^$<day> = (\d**2)\.$<mon> = (\d**2)\.$<year> = (\d**4)/ { say $<day> }
「16」
> if $s ~~ /^(\d**2)\.(\d**2)\.(\d**4)/ { say [=10=] }
「16」

问题出在使用正则表达式的地方 - 即 <$dReg>。不捕获以非标识符开头的任何形式的断言语法。解决方案是引入一个名称以供捕获。例如,这个:

my $s = '16.01.2020 09:18 286';
my $dReg = /^(\d**2)\.(\d**2)\.(\d**4)/;
say $s ~~ /<dreg=$dReg>/;

结果:

「16.01.2020」
 dreg => 「16.01.2020」
  0 => 「16」
  1 => 「01」
  2 => 「2020」

然后您将以 $<dreg>[0] 的身份访问捕获。这是因为每个级别的规则调用都意味着 Raku 正则表达式中的嵌套级别。这就是允许他们扩展到完整语法的原因。

请注意,如果您只想匹配包含正则表达式的变量,那完全没问题,而且效率更高。在这种情况下,您将直接获得捕获。例如,这个:

my $s = '16.01.2020 09:18 286';
my $dReg = /^(\d**2)\.(\d**2)\.(\d**4)/;
say $s ~~ $dReg;

产生:

「16.01.2020」
 0 => 「16」
 1 => 「01」
 2 => 「2020」

查看 jnthn 的回答。

另一种选择是声明一个命名的正则表达式(这与具有名称且恰好包含正则表达式的变量不同)。例如:

my $input = 'foo';
my regex dreg { 'foo' }
if $input ~~ /<dreg>/ { say $<dreg> } # 「foo」