焉知非鱼

大雨像阳光般倾落, 边失去边拥有着

正则表达式中的尖括号

2017-09-15


在正则表达式外面, <> 表现的更像单引号。我浅薄的认知告诉我, 在正则表达式内部, <> 允许求值和代码插值:

# 在正则表达式外面, <> 表现得像单引号:
> 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」

因为在正则表达式中允许有数组变量, 所以我猜测 raku 正则引擎在数组两边含有 <> 时将数组展开成 OR 了。我还猜测在用户自定义的字符类 <[]> 中, <> 中的 [] 有点像匿名数组, 和下面的 @a 类似, 并且数组(字符类中的字符)的内容扩展为 OR’s:

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」

还有字符类展开:

> 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 源代码? 谢谢。

Answer

在正则外面,<> 表现得像 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'

推荐阅读 语言:引号结构 这个更深入的主题。

这个和正则表达式中的 <> 没有关系。

在简单的 Raku 代码中, <> 在正则中并不是那么有用, 并且 qw 在正则中也不是那么有用。

在正则中可以插入某些代码到正则表达式中; 这有点像宏, 或函数调用。

/<{ split ';', 'a;b;c' }>/;
/ [ "a" | "b" | "c" ] /;
# 'b' ~~  m/<{ split ';', 'a;b;c' }>/;
# say "zzonezz" ~~ m/ <{ say "foo"; "one";}> /

(注意 | 会同时尝试所有的分支而 || 首先尝试最左侧的分支, 紧接着是下一个, 等等。即 || 和 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 / 会把数组中的每个元素都作为一个分支:

/ <@a> /
/ [ "one" | "two" ] /
/ <?{ 1 > 0 }> /

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

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

最后那俩不是很准确, 但是是一种思路。

<> 还经常用于调用 regex “methods”.

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