Perl版本:5.16.01
我正在读一本关于正则表达式的书,它基于perl 5.8
这本书说s/^\s*$/blabla/mg
可以匹配并替换多个空白行。
但是当我感到惋惜时,我得到了一个令人困惑的结果。
code:
$text = "c\n\n\n\n\nb";
$text =~ s/^\s*$/<p>/mg;
print "$text";
结果如下:
C:\Users\Administrator\Desktop\regex>perl t2h.pl
c
<p><p>
b
我想知道为什么我没有得到一个<p>
但是在'c'和'b'之间加倍。 Perl的/$/
在5.8之后会发生变化吗?
答案 0 :(得分:4)
这里的教训是警惕与零宽度模式匹配的正则表达式,你可能会得到意想不到的结果。
我们可以通过显示两个替换的匹配,匹配和匹配来查看此处发生的情况:
use strict;
use warnings;
my $text = "c\n\n\n\nb";
$text =~ s{^\s*$}{
printf qq{<"%s" - "%s" - "%s">\n}, map s/\n/\\n/gr, ($`, $&, $');
"<p>"
}emg;
$text =~ s/\n/\\n/g;
print qq{Result: "$text"};
输出<"Prematch" - "Match" - "Postmatch">
:
<"c\n" - "\n\n" - "\nb">
<"c\n\n\n" - "" - "\nb">
Result: "c\n<p><p>\nb"
基本上,正则表达式从第2位到第4位匹配,捕获2个返回字符。在替换之后,它开始从位置4搜索并匹配零宽度模式,因此添加第二个<p>
。
这不直观的原因之一是因为我们的正则表达式替换了位置2和位置的\n\n
。 3,<p>
。但是,lookbehind断言(^
是特殊变体)会将字符串视为原始字符串,而不是因为它可能已被/g
正则表达式的先前传递所取代。因此,当在第4位匹配时,正则表达式会在其后面看c\n\n\n
而不是c\n<p>
(如上面的输出所示),因此会立即再次匹配^
和$
在它前面没有间距。
解决方法是在此实例中使用+
而不是*
,不允许零宽度模式。
次要示例
另一个例子是以下更简单的正则表达式
my $text = "caab";
$text =~ s/a*/<p>/g;
print $text;
输出:
<p>c<p><p>b<p>
此匹配的位置细分如下:
0 c - match a zero width pattern
1 a - Match a 2 character pattern
2 a
3 b - Match a zero width pattern
4 $ - match a zero width pattern
因此,最后一课只是要警惕与零宽度模式匹配的正则表达式。
答案 1 :(得分:0)
量词*匹配0次或更多次, 量词?匹配1次或更多次。
所以你的正则表达式应该写成s/^\s+$/<p>/mg
答案 2 :(得分:0)
你可以试试这个:
#!/usr/bin/perl
$text = "c\n\n\n\n\nb";
$text =~ s/[\r\n]//g;
print $text;