在Perl中,如何编写一个正则表达式,每个字符串最多只能替换N个匹配项?
即,我正在寻找s/aa/bb/;
和s/aa/bb/g;
之间的中间地带。我想允许多次替换,但最多只允许N次。
答案 0 :(得分:5)
我可以想到三种可靠的方法。第一种是在第N次与自身匹配后替换所有内容。
my $max = 5;
$s =~ s/(aa)/ $max-- > 0 ? 'bb' : $1 /eg;
如果有超过N个匹配,则效率不高。为此,我们需要将循环移出正则表达式引擎。接下来的两种方法是这样做的。
my $max = 5;
my $out = '';
$out .= $1 . 'bb' while $max-- && $in =~ /\G(.*?)aa/gcs;
$out .= $1 if $in =~ /\G(.*)/gcs;
而这次,就地:
my $max = 5;
my $replace = 'bb';
while ($max-- && $s =~ s/\G.*?\Kaa/$replace/s) {
pos($s) = $-[0] + length($replace);
}
你可能想做类似
的事情my $max = 5;
$s =~ s/aa/bb/ for 1..$max;
但对于其他模式和/或替换表达式,该方法将失败。
my $max = 5;
$s =~ s/aa/ba/ for 1..$max; # XXX Turns 'aaaaaaaa'
# into 'bbbbbaaa'
# instead of 'babababa'
当然,每次从字符串的开头开始都可能很昂贵。
答案 1 :(得分:2)
你想要的东西在正则表达式中是不可能的。但你可以把替换放在for循环中:
my $i;
my $aa = 'aaaaaaaaaaaaaaaaaaaa';
for ($i=0;$i<4;$i++) {
$aa =~ s/aa/bb/;
}
print "$aa\n";
结果:
bbbbbbbbaaaaaaaaaaaa
答案 2 :(得分:1)
您可以使用/e
标志来评估右侧作为表达式:
my $n = 3;
$string =~ s/(aa)/$n-- > 0 ? "bb" : $1/ge;
答案 3 :(得分:1)
这是使用/ e修饰符的解决方案,您可以使用它 用于生成替换字符串的perl代码:
my $count = 0; $string =~ s{ $pattern } { $count++; if ($count < $limit ) { $replace; } else { $&; # faking a no-op, replacing with the original match. } }xeg;
使用perl 5.10或更高版本,您可以放弃$&amp; (这很奇怪 性能并发症)并通过/ p修饰符使用$ {^ MATCH}
$string =~ s{ $pattern } { $count++; if ($count < $limit ) { $replace; } else { ${^MATCH}; } }xegp;
太糟糕了,你不能这样做,但你不能:
last if $count >= $limit;