命名正则表达式在 raku 中捕获失败

hsm*_*ers 5 regex 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 $0 }
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 $0 }
?16?
Run Code Online (Sandbox Code Playgroud)

Jon*_*ton 8

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

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

结果是:

?16.01.2020?
 dreg => ?16.01.2020?
  0 => ?16?
  1 => ?01?
  2 => ?2020?
Run Code Online (Sandbox Code Playgroud)

然后,您可以将捕获作为$<dreg>[0]. 这是因为规则调用的每个级别都意味着 Raku 正则表达式中的嵌套级别。这使他们能够扩展到完整的语法。

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

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

产生:

?16.01.2020?
 0 => ?16?
 1 => ?01?
 2 => ?2020?
Run Code Online (Sandbox Code Playgroud)


rai*_*iph 5

请参阅 jnthn 的回答。

\n\n

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

\n\n
my $input = 'foo';\nmy regex dreg { 'foo' }\nif $input ~~ /<dreg>/ { say $<dreg> } # \xef\xbd\xa2foo\xef\xbd\xa3\n
Run Code Online (Sandbox Code Playgroud)\n