Jac*_*lin 5 regex perl multiline regex-group
这与 perl 多行正则表达式有关,用于分隔段落内的注释,但仅关注正则表达式语法的单个问题。
根据perlre: Modifiers,/m正则表达式修饰符意味着
将匹配的字符串视为多行。也就是说,将“^”和“$”从匹配字符串第一行的开头和最后一行的结尾更改为匹配字符串中每一行的开头和结尾。
因此,使用以下代码:
#!/usr/bin/perl
use strict; use warnings;
$/ = ''; # one paragraph at a time
while(<DATA>)
{
print "original:\n";
print;
s/^([^B]*)(B.*?)$/>$1|$2</mg;
print "\n\nafter substitution:\n";
print;
}
__DATA__
aaaaBaBaBB
bbbbBbadbe
cccc
dddd
eeeeBeeeee
ffff
gggg
Run Code Online (Sandbox Code Playgroud)
我期望正则表达式引擎的行为如下。
第 1 行:匹配,因为它会找到该行开头和结尾之间的两种模式。
第 2 行:同上。
第 3 行:不匹配。第一个正则表达式组(在第一组括号中)匹配。但是当我们到达该行的末尾时,我们仍在寻找B,以开始第二个正则表达式组。由于我们已经指定了/m,因此该特定行的末尾意味着我们已到达$但未满足整个模式。
第 4 行:我们开始一个新行,因此我们遇到一个新的^. 再次,没有匹配。
第 5 行:匹配。两个正则表达式组都位于行的开头和结尾之间,即在^和 之间$,完全按照指定。
因此我希望看到
>aaaa|BaBaBB<
>bbbb|Bbadbe<
cccc
dddd
>eeee|Beeeee<
ffff
gggg
Run Code Online (Sandbox Code Playgroud)
相反,在第 3 行,引擎似乎忽略了 行尾并搜索了它。它将第 3--5 行视为一行,如果我们愿意突然忽略$表示行尾的行,则将满足正则表达式。这是我们看到的:
>aaaa|BaBaBB<
>bbbb|Bbadbe<
>cccc
dddd
eeee|Beeeee<
ffff
gggg
Run Code Online (Sandbox Code Playgroud)
这与规范如何一致/m?此行为记录在哪里?
> perl --version
This is perl 5, version 18, subversion 4 (v5.18.4) built for darwin-thread-multi-2level
(with 2 registered patches, see perl -V for more detail)
Run Code Online (Sandbox Code Playgroud)
当正则表达式可以以多种不同的方式匹配字符串时,我们可以使用上面的原理来预测正则表达式将匹配哪种方式:
原则 0:作为一个整体,任何正则表达式都将在字符串中最早的可能位置进行匹配。
原则 1:在 a|b|c... 替换中,将使用允许匹配整个正则表达式的最左边的替换选项。
原则 2:最大匹配量词 '?' 、 '*' 、 '+' 和 {n,m} 通常会匹配尽可能多的字符串,同时仍然允许整个正则表达式匹配。
原则 3:如果正则表达式中有两个或多个元素,则最左边的贪婪量词(如果有)将匹配尽可能多的字符串,同时仍然允许整个正则表达式匹配。下一个最左边的贪婪量词(如果有)将尝试尽可能多地匹配剩余可用的字符串,同时仍然允许整个正则表达式匹配。依此类推,直到满足所有正则表达式元素。
正如我们在上面所看到的,原则 0 优先于其他原则。正则表达式将尽早匹配,其他原则决定正则表达式如何在最早的字符位置匹配。
[...]
我们可以修改上面的原则 3 以考虑非贪婪量词:原则 3:如果正则表达式中有两个或多个元素,则最左边的贪婪(非贪婪)量词(如果有)将匹配尽可能多(少)的字符串,同时仍然允许整个正则表达式匹配。下一个最左边的贪婪(非贪婪)量词(如果有)将尝试匹配尽可能多(少)的剩余可用字符串,同时仍然允许整个正则表达式匹配。依此类推,直到满足所有正则表达式元素。
所以对于这个案例
my $str = 'cccc
dddd
eeeeBeeeee
ffff
gggg';
$str =~ s/^([^B]*)(B.*?)$/>$1|$2</m;
Run Code Online (Sandbox Code Playgroud)
我们使用原则 0 和原则 3,因此它将在 中的起始位置(位置 0)匹配$str。根据原则3,我们从最左边的元素开始:
^([^B]*)
Run Code Online (Sandbox Code Playgroud)
它将匹配“尽可能多的字符串,同时仍然允许整个正则表达式匹配”。,这意味着它将能够从字符串的开头到第一个 进行匹配B。然后引擎考虑下一个元素
(B.*?)$
Run Code Online (Sandbox Code Playgroud)
尽管如此,根据原则 3:它将匹配“尽可能少的字符串,同时仍然允许整个正则表达式匹配”。因此它将匹配从 到B找到的第一个新行。