Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Raku regex: How to know which group was captured at an alternation

With perl (and almost any regex flavour), every group is numbered sequentially.

So for example, this code:

'bar' =~ m/(foo)|(bar)/;

print $1 // 'x'; # (1-based index)
print $2 // 'x'; # (1-based index)

prints xbar

However, with Raku it behaves like there was a branch reset group wrapping the whole regex:

'bar' ~~ m/(foo)|(bar)/;

print $0 // 'x'; # (0-based index)
print $1 // 'x'; # (0-based index)

prints barx

I'm ok with this behaviour :). However, it is sometimes useful to know which group was captured under an alternation.

How can I know the group with raku?

like image 714
Julio Avatar asked Oct 16 '20 19:10

Julio


Video Answer


1 Answers

There are a few ways to do, with varying degrees of utility.

One way would be to explicitly tell Raku what you want the numbers to be:

'bar' ~~ m/$1=(foo)|$2=(bar)/;

If you extend the regex, counting will continue at $3.

A less-recommendable way to do this would be to sneak in an extra set of parentheses:

'bar' ~~ m/(foo)|()(bar)/;

foo will match the first one in $0 and $1 will be undefined, and bar will match the $1 with $0 being empty (but not undefined). TIMTOWTDI but this is not a good one ;-)

Another way could be to use a flag:

 my $flag;
'bar' ~~ m/(foo {$flag = 'first'} ) | (bar {$flag = 'second'} )/;

The flag will be set based on the match. This can actually be a not-terrible way to do things, especially if your flag is binary and you will have some logic that you'll run over it.

Another similar way would be to take advantage of the .make/.made that's normally used in action classes, but can still be used inline too:

'bar' ~~ m/(foo {make 'first'} ) | (bar {make 'second'} )/;
say $0.made; # 'second'

This one is nice if you have a lot of metadata you want to associate with it (but probably overkill for just knowing which one was chosen).

like image 110
user0721090601 Avatar answered Oct 02 '22 08:10

user0721090601