Perl 6 中正则表达式中 <> 和匿名数组的特殊含义

Special meaning of <> and anonymous arrays inside regex in Perl 6

在正则表达式之外,<> 的行为或多或少类似于单引号。我的肤浅理解似乎告诉我,在正则表达式中,<> 允许对代码进行评估和插值:

# Outside regex, <> acts like single quotes:
> my $x = <{"one"}>
{"one"}
> $x.WHAT
(Str)

# Inside regex, <> evaluates and interpolates:
> my $b="one";
one
> say "zonez" ~~ m/ <{$b}> /  # Evaluates {$b} then quotes: m/ one /
「one」
> say "zonez" ~~ m/ <$b> /    # Interpolates and quotes without {}
「one」

因为正则表达式中允许使用数组变量,我怀疑 Perl 6 正则表达式引擎在数组周围有 <> 内部正则表达式时将数组扩展为 OR。

我还怀疑在用户定义的字符class、<[ ]>中,<>中的数组[]或多或少像匿名数组一样工作,类似于下面的@a,并且数组的内容(字符 class 中的字符)扩展为 OR。

my @a = $b, "two";
[one two]
> so "zonez" ~~ m/ @a /;
True
> say "ztwoz" ~~ m/ <{[$b, "two"]}> / # {} to eval array, then <> quotes
「two」
> say "ztwoz" ~~ m/ <{@a}> /
「two」
> say "ztwoz" ~~ m/ <@a> /
「two」
> say "ztwoz" ~~ m/ one || two /  # expands @a into ORs: [||] @a;
# [||] is a reduction operator;
「two」

和 char class 扩展:

> say "ztwoz" ~~ m/ <[onetw]> / # like [||] [<o n e t w>];
「t」
> say "ztwoz" ~~ m/ o|n|e|t|w /
「t」
> my @m = < o n e t w >
[o n e t w]
> say "ztwoz" ~~ m/ @m /
「t」

Rakudo源码我没看过,理解有限。我无法在正则表达式中构造匿名数组来证明 <> 确实在正则表达式中构造数组。

那么,正则表达式中的 <> 有什么特别之处吗?或者我应该研究一下 Rakudo 源代码(我现在真的尽量不要这样做)?

在正则表达式之外 <> 的行为类似于 qw<>,即它在空格上引用和拆分。

say <a b    c>.perl;
# ("a", "b", "c")

可以扩展为

q :w 'a b    c'

Q :q :w 'a b    c'

Q :single :words 'a b    c'

我建议阅读 Language: Quoting Constructs,因为这是一个更广泛的主题,无法在此处讨论。

这与 <> 在正则表达式中所做的几乎无关。

在正则表达式中使用 <> 在基本 Perl 6 代码中没有用,而 qw 在正则表达式中用处不大。所以这些字符起着双重作用,主要是因为 ASCII 中非字母和非数字字符很少。它唯一一次表现得像 qw 是紧跟在 < 之后的字符是空白字符。


在正则表达式内部,它可以被认为是将一些代码注入到正则表达式中;有点像宏或函数调用。

/<{ split ';', 'a;b;c' }>/;
/ [ "a" | "b" | "c" ] /;

( 请注意,| 同时尝试所有交替,而 || 首先尝试最左边的一个,然后是下一个,等等。也就是说 || 基本上可以工作| 在 Perl 5 和 PCRE 中的方式。)

/<:Ll - [abc]>/
/ [d|e|f|g|h|i|j|k|l|m|n|o|p|q|r|s|t|u|v|w|x|y|z] / # plus other lowercase letters
/ <@a> /
/ [ "one" | "two" ] /

请注意 / @a / 也分解为相同的结构。

/ <?{ 1 > 0 }> /

# null regex always succeeds
/ [ '' ] /
/ <?{ 1 == 0 }> /

# try to match a character after the end of the string
# (can never succeed)
/ [ $ : . ] /

最后两个不太准确,但可能是一种有用的思考方式。


也用于调用正则表达式"methods".

grammar Foo {
  token TOP { <alpha> } # calls Grammar.alpha and uses it at that point
}

如果你注意到我总是用 [] 包围替换,因为它总是像一个独立的子表达式。

技术上 none 这些都是按照我展示的方式实现的,它只是一个更容易解释的理论模型。

在正则表达式中 <> 用于我倾向于称之为 "generalized assertions" 的内容。每当您使用正则表达式匹配某些内容时,您都会对字符串的外观做出一系列断言。如果所有断言都为真,则整个正则表达式匹配。例如,/ foo / 断言字符串 "foo" 出现在被匹配的字符串中; / f o* / 断言字符串应包含一个 "f" 后跟零个或多个 "o",等等

在任何情况下,对于一般化断言,Rakudo Perl 6 使用紧跟在 < 之后的字符来确定正在进行哪种断言。如果 < 之后的字符是字母(例如 <foo>),则表示一个命名的子规则;如果 < 之后的字符是 {,它是一个包含要插入到模式中的代码的断言(例如,<{ gen_some_regex(); }>);如果 < 之后的字符是 [,则它是一个字符 class;如果 < 之后的字符是 :,那么它期望匹配 Unicode 属性(例如,<:Letter>);如果 < 之后的字符是 ?!,您将分别得到正零宽度断言和负零宽度断言;等等

最后,在正则表达式之外,<> 充当 "quote words"。如果 < 后面的字符是空白字符,在正则表达式中,它也将作为一种 "quote words":

> "I'm a bartender" ~~ / < foo bar > /
「bar」

这是匹配的,就好像它是一个交替,即 < foo bar > 将匹配 foobar 之一,就好像你写了 foo | bar