Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Named regex fails capture in raku

Tags:

regex

raku

Could someone explain why captures (named and un-named) don't seem to work in named regexes? I'm expecting that It is something I'm doing wrong, but if so, I don't see it. Here is captured text from the raku repl as my short-form example.

> 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」
like image 857
hsmyers Avatar asked Mar 23 '20 17:03

hsmyers


2 Answers

The problem is at the point the regex is used - that is, the <$dReg>. Any form of assertion syntax starting with a non-identifier does not capture. The solution is to introduce a name for it to be captured under. For example, this:

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

Results in:

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

You'd then access the captures as $<dreg>[0]. This is because each level of rule call implies a nesting level in Raku regexes. This is what allows them to scale up to full grammars.

Note that it's entirely fine - and more efficient - to match against the variable containing the regex if that's all you wish to do. In that case, you'll get the captures directly. For example, this:

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

Produces:

「16.01.2020」
 0 => 「16」
 1 => 「01」
 2 => 「2020」
like image 175
Jonathan Worthington Avatar answered Nov 15 '22 11:11

Jonathan Worthington


See jnthn's answer.

Another option is to declare a named regex (which isn't the same thing as a variable that has a name and happens to contain a regex). For example:

my $input = 'foo';
my regex dreg { 'foo' }
if $input ~~ /<dreg>/ { say $<dreg> } # 「foo」
like image 33
raiph Avatar answered Nov 15 '22 11:11

raiph