在 Perl 6 中使用 sub 构建正则表达式
Building a regex with sub in Perl 6
学习 后,我尝试使用 sub
构建我的第一个正则表达式,但我又一次被卡住了。对于下面的复杂规则,我深表歉意,我已尽力简化它们。我至少需要一些线索来解决这个问题。
regex
应该由交替组成,每个交替由left
、middle
和right
组成,其中left
和right
应该成对出现,middle
的变体取决于选择哪个 right
。
Pairs
的数组包含 left
和 right
对:
my Pair @leftright =
A => 'a',
...
Z => 'z',
;
Middle
从哈希中读取变体:
my Regex %middle =
z => / foo /,
a => / bar /,
m => / twi /,
r => / bin /,
...
;
如果 right
是 z
,%middle<a>
应该选择 %middle<z>
— 如果 right
是 a
,等等
因此,生成的正则表达式应该是
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)
...
}
它应该匹配 Abara
和 Zfooz
.
如何构建 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)}>
}
比赛结束后,我需要知道 left
、middle
和 right
的值:
"Abara" ~~ &word;
say join '|', $<left>, $<middle>, $<right> # A|bar|a
我还不能使用 token
来做到这一点,但是这里有一个使用 EVAL
和 Regex
的解决方案(而且我正在使用 %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?
学习 sub
构建我的第一个正则表达式,但我又一次被卡住了。对于下面的复杂规则,我深表歉意,我已尽力简化它们。我至少需要一些线索来解决这个问题。
regex
应该由交替组成,每个交替由left
、middle
和right
组成,其中left
和right
应该成对出现,middle
的变体取决于选择哪个 right
。
Pairs
的数组包含 left
和 right
对:
my Pair @leftright =
A => 'a',
...
Z => 'z',
;
Middle
从哈希中读取变体:
my Regex %middle =
z => / foo /,
a => / bar /,
m => / twi /,
r => / bin /,
...
;
如果 right
是 z
,%middle<a>
应该选择 %middle<z>
— 如果 right
是 a
,等等
因此,生成的正则表达式应该是
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)
...
}
它应该匹配 Abara
和 Zfooz
.
如何构建 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)}>
}
比赛结束后,我需要知道 left
、middle
和 right
的值:
"Abara" ~~ &word;
say join '|', $<left>, $<middle>, $<right> # A|bar|a
我还不能使用 token
来做到这一点,但是这里有一个使用 EVAL
和 Regex
的解决方案(而且我正在使用 %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?