在 Perl 6 中使用 sub 构建正则表达式

Building a regex with sub in Perl 6

学习 后,我尝试使用 sub 构建我的第一个正则表达式,但我又一次被卡住了。对于下面的复杂规则,我深表歉意,我已尽力简化它们。我至少需要一些线索来解决这个问题。

regex应该由交替组成,每个交替由leftmiddleright组成,其中leftright 应该成对出现,middle 的变体取决于选择哪个 right

Pairs 的数组包含 leftright 对:

my Pair @leftright =
  A => 'a',
  ...
  Z => 'z',
  ;

Middle 从哈希中读取变体:

my Regex %middle = 
  z => / foo /,
  a => / bar /,
  m => / twi /,
  r => / bin /,
  ...
  ;
如果 rightz%middle<a> 应该选择

%middle<z> — 如果 righta,等等

因此,生成的正则表达式应该是

my token word {
    | A <%middle[a]> a
    | Z <%middle[z]> z
    | ...
}

或者更一般地说

my token word {
    | <left=@leftright[0].key> 
      <middle=%middle{@leftright[0].value}> 
      <right=@leftright[0].value> 
    | (the same for index == 1)
    | (the same for index == 2)
    | (the same for index == 3)
 ...
}

它应该匹配 AbaraZfooz.

如何构建 token word(可以在 grammar 中使用)和 sub 来获取 @leftright 中的每一对,将合适的 %middle{} 取决于 right 的值,然后将它们合并为一个 regex

my Regex sub sub_word(Pair @l_r, Regex %m) {
...
}
my token word {
    <{sub_word(@leftright, %middle)}> 
}

比赛结束后,我需要知道 leftmiddleright 的值:

"Abara" ~~ &word;
say join '|', $<left>, $<middle>, $<right> # A|bar|a

我还不能使用 token 来做到这一点,但是这里有一个使用 EVALRegex 的解决方案(而且我正在使用 %middle 作为Str 的散列而不是 Regex 的散列):

my Regex sub build_pattern (%middle, @leftrigth) {
    my $str = join '|', @leftright.map(
        {join ' ',"$<left>='{$_.key}'", "$<middle>='{%middle{$_.value}}'", "$<right>='{$_.value}'"});
    );
    my Regex $regex = "rx/$str/".EVAL;

    return $regex;
}

my Regex $pat = build_pattern(%middle, @leftright);

say $pat;
my $res = "Abara" ~~ $pat;
say $res;

输出:

rx/$<left>='A' $<middle>='bar' $<right>='a'|$<left>='Z' $<middle>='foo' $<right>='z'/
「Abara」
 left => 「A」
 middle => 「bar」
 right => 「a」

有关我为什么选择使用 EVAL 的更多信息,请参阅 How can I interpolate a variable into a Perl 6 regex?