尝试使用/ ^ \ s * $ /匹配多个空行并将其替换失败并获得令人困惑的结果

时间:2014-04-24 03:43:09

标签: regex perl

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之后会发生变化吗?

3 个答案:

答案 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;

DEMO http://ideone.com/WmVFHz