Is it possible to have a capture within an interpolated regex?

Dan*_*ita 8 regex string-interpolation raku

I wanted to generate regex from an existing list of values, but when I attempted to use a capture within it, the capture was not present in the match. Is it not possible to have a capture using interpolation, or am I doing something wrong?

my @keys = <foo bar baz>;
my $test-pattern = @keys.map({ "<$_>" }).join(' || ');

grammar Demo1 {
  token TOP {
    [
      || <foo>
      || <bar>
      || <baz>
    ] ** 1..* % \s+
  }

  token foo { 1 }
  token bar { 2 }
  token baz { 3 }
}

grammar Demo2 {
  token TOP {
    [ <$test-pattern> ] ** 1..* % \s+
  }

  token foo { 1 }
  token bar { 2 }
  token baz { 3 }
}

say $test-pattern, "\n" x 2, Demo1.parse('1 2 3'), "\n" x 2, Demo2.parse('1 2 3');
Run Code Online (Sandbox Code Playgroud)
<foo> || <bar> || <baz>

?1 2 3?
 foo => ?1?
 bar => ?2?
 baz => ?3?

?1 2 3?
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 6

确定形式的原子是否<...>捕获的规则是它是否以字母或下划线开头。

如果断言以字母或下划线开头,则预期/解析标识符并使​​用该标识符作为封闭匹配对象中的键来捕获匹配。例如,<foo::baz-bar qux>以字母开头并在键下捕获foo::baz-bar

如果断言确实以字母或下划线开头,则默认情况下它不会捕捉。


要捕获第一个字符不是字母或下划线的断言的结果,您可以将其放在括号中或命名为:

( <$test-pattern> ) ** 1..* % \s+
Run Code Online (Sandbox Code Playgroud)

或者,命名断言:

<test-pattern=$test-pattern> ** 1..* % \s+
Run Code Online (Sandbox Code Playgroud)

或(只是另一种具有相同命名效果的方式):

$<test-pattern>=<$test-pattern> ** 1..* % \s+
Run Code Online (Sandbox Code Playgroud)

如果您所做的只是在括号中放置一个否则无法捕获的断言,那么您还没有为该断言打开捕获。相反,您只是将它包装在一个外部 capture 中。断言保持非捕获状态,并且丢弃非捕获断言的任何子捕获数据

因此,上面显示的第一个解决方案的输出(将<$test-pattern>断言包装在括号中)是:

?1 2 3?
 0 => ?1?
 0 => ?2?
 0 => ?3?
Run Code Online (Sandbox Code Playgroud)

有时这就是您想要简化解析树和/或节省内存的原因。

相反,如果你的名字与任一的上面示出的名为形式的另外非捕获断言,然后通过这样做你把它转换成摄像断言,这意味着任何捕获细节将被保留。因此,命名的解决方案产生:

?1 2 3?
 test-pattern => ?1?
  foo => ?1?
 test-pattern => ?2?
  bar => ?2?
 test-pattern => ?3?
  baz => ?3?
Run Code Online (Sandbox Code Playgroud)