How to put a sub inside a regex in Perl 6?

可紊 提交于 2019-12-01 20:19:13

The <{...}> construct runs Perl 6 code inside a regex, and evaluates the result as a regex:

my sub nplus1($n) {$n +1} my regex nnplus1 { ^ (\d+) <{ nplus1($0) }> $ } say so '23' ~~ &nnplus1; # Output: True say so '22' ~~ &nnplus1; # Output: False

Keep in mind that regexes are subs. So don't call your matcher a sub—be more specific and call it a regex. Yes, you can pass arguments to regex/token/rule. It's really important to do this when you match languages that change their state as you parse. For example, in YAML, you can parse "data[0]: 17". After that, the next line can start with "data[1]" but not "data[2]". So passing extra info as parameters is useful.

Also note that when you convert this to a regex, some things change. $n+1 will take on a new meaning (which is wrong). However, simple variables are still interpolated, so if you declare it as a new variable within the regex body with :my $npp = .... But even then, you'll find it still doesn't work. When you add a helper statement like {say "n is $n"}, you'll see you're not getting passed a valid parameter. This is because in code-like contexts without braces (when you use an expression as an argument to another matcher), rakudo does not update the match variable. When you add braces, the current match variable is recomputed or re-cached. This hack looks like a typo, so I suggest you add a comment that explains the empty braces. The final code is this:

my regex nplus1($n) {
 :my $npp=$n+1;
 $npp
}
my regex nnplus1 { (\d+) {} <nplus1($0)> }
say "123124" ~~ &nnplus1;

In this case (which is basically recursion), I like to keep things neater by changing data in the arguments instead of changing data in the function body: <nplus1($0+1)> instead of defining :my $npp = $n+1;.

Based on the Regex interpolation docs as well as on piojo's answer and Håkon Hægland's comment, it seems I've managed to do what I wanted:

my sub nplus1($n) {
 $n+1;
}
my regex nnplus1 { (\d+) {} <nplus1=$(nplus1($0))> }
say "123124" ~~ &nnplus1;

Output:

「123124」
 0 => 「123」
 nplus1 => 「124」

Or we can move the {} to enclose the interpolated sub:

my sub nplus1($n) {
 $n+1;
}
my regex nnplus1 { (\d+)  <nplus1={nplus1($0)}> }
say "123124" ~~ &nnplus1;

(the output will be the same)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!