Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl 6: Lookahead with capture

I'm attempting to write a Perl 6 regex for this code-golf challenge that splits a string with the rules:

  • Sequences of the same character with length 3 or less will be grouped together
  • But 4 or more will result in the first two being grouped before checking the rest

For example:

66667888    -> '66', '66, '7', '888'
19999999179 -> '1', '99', '99', '999', '1', '7', '9'

I thought the regex m:g/(.)[$0$0<!$0>|$0?]/ would work, but using a capture in the negative lookahead seems to break it, and I can't figure out how to use it properly.

Depending on how I use it, it either loops forever, throws the error Cannot resolve caller INTERPOLATE_ASSERTION, or returns the wrong result. Is there a proper way to use captures in lookaheads, or is this a bug?

like image 936
Jo King Avatar asked Aug 16 '19 01:08

Jo King


1 Answers

According to Capturing section you need to use a code block to make these backreferences visible inside a regex:

These capture variables are only available outside the regex... In order to make them available inside the regex, you need to insert a code block behind the match; this code block may be empty if there's nothing meaningful to do

Use

given "19999999179" {
  for m:g/(.) {} :my $c = $0; ([ $c$c<!$c> | $c? ])/  -> $match {
    say ~$match;
  }
}

Results:

1
99
99
999
1
7
9

See the Perl6 demo.

In this scenario, you may contract the pattern to m:g/(.) {} [ $0$0<!$0> | $0? ]/:

my @matches;
given "19999999179" {
  for m:g/(.) {} [ $0$0<!$0> | $0? ]/ -> $match {
    @matches.push: (~$match);
  }
}
say @matches;

Results in [1 99 99 999 1 7 9].

See this Perl6 demo.

like image 188
Wiktor Stribiżew Avatar answered Jan 04 '23 07:01

Wiktor Stribiżew