这里是详细的解释为什么您的代码不起作用。
/g 修饰符将正则表达式的行为更改为“全局匹配”。这将匹配字符串中所有出现的模式。但是,如何进行这种匹配取决于 context。 Perl 中的两个(主要)上下文是 list context(复数)和 scalar context(单数)。
在列表上下文中,全局正则表达式匹配返回所有匹配子字符串的列表,或所有匹配捕获的平面列表:
my $_ = "foobaa";
my $regex = qr/[aeiou]/;
my @matches = /$regex/g; # match all vowels
say "@matches"; # "o o a a"
在标量上下文中,匹配似乎返回一个描述正则表达式是否匹配的 perl 布尔值:
my $match = /$regex/g;
say $match; # "1" (on failure: the empty string)
然而,正则表达式变成了一个迭代器。每次执行正则表达式匹配时,正则表达式从字符串中的当前位置开始,并尝试匹配。如果匹配,则返回 true。如果匹配失败,那么
- 匹配返回 false,并且
- 字符串中的当前位置设置为开头。
由于字符串中的位置被重置,下一次匹配将再次成功。
my $match;
say $match while $match = /$regex/g;
say "The match returned false, or the while loop would have go on forever";
say "But we can match again" if /$regex/g;
第二个效果——重置位置——可以通过附加的/c 标志来取消。
可以通过pos函数访问字符串中的位置:pos($string)返回当前位置,可以像pos($string) = 0一样设置。
正则表达式也可以使用\G 断言锚定在当前位置,就像^ 将正则表达式锚定在字符串的开头。
这种m//gc 风格的匹配使得编写分词器变得容易:
my @tokens;
my $_ = "1, abc, 2 ";
TOKEN: while(pos($_) < length($_)) {
/\G\s+/gc and next; # skip whitespace
# if one of the following matches fails, the next token is tried
if (/\G(\d+)/gc) { push @tokens, [NUM => $1]}
elsif (/\G,/gc ) { push @tokens, ['COMMA' ]}
elsif (/\G(\w+)/gc) { push @tokens, [STR => $1]}
else { last TOKEN } # break the loop only if nothing matched at this position.
}
say "[@$_]" for @tokens;
输出:
[NUM 1]
[COMMA]
[STR abc]
[COMMA]
[NUM 2]