Regex 一行最多只能替换N个匹配项

Regex 一行最多只能替换N个匹配项,regex,perl,Regex,Perl,在Perl中,如何编写一个正则表达式,每个字符串最多只替换N个匹配项 也就是说,我正在寻找s/aa/bb/之间的中间地带和s/aa/bb/g。我想允许多个替换,但最多只能替换N次。正则表达式中不可能实现您想要的替换。但您可以将替换项放入for循环: my $i; my $aa = 'aaaaaaaaaaaaaaaaaaaa'; for ($i=0;$i<4;$i++) { $aa =~ s/aa/bb/; } print "$aa\n"; 我的$i; 我的$aa='aaaaaaa

在Perl中,如何编写一个正则表达式,每个字符串最多只替换N个匹配项


也就是说,我正在寻找
s/aa/bb/之间的中间地带
s/aa/bb/g。我想允许多个替换,但最多只能替换N次。

正则表达式中不可能实现您想要的替换。但您可以将替换项放入for循环:

my $i;
my $aa = 'aaaaaaaaaaaaaaaaaaaa';
for ($i=0;$i<4;$i++) {
    $aa =~ s/aa/bb/;
}
print "$aa\n";
我的$i;
我的$aa='aaaaaaaaaaaaaaaa';

对于($i=0;$i可以使用
/e
标志,该标志将右侧作为表达式进行计算:

my $n = 3;    
$string =~ s/(aa)/$n-- > 0 ? "bb" : $1/ge;

我可以想出三种可靠的方法。第一种是在第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'

当然,每次从字符串的开头开始都会很昂贵。

这里有一个使用/e修饰符的解决方案,您可以使用它 生成替换字符串的perl代码:

我的$count=0; $string=~s{$pattern} { $count++; 如果($count<$limit){ $replace; }否则{ $&;#假装无操作,替换为原始匹配。 } }xeg;

使用perl 5.10或更高版本,您可以删除$&(它的 并通过/p修饰符使用${^MATCH}

$string=~s{$pattern} { $count++; 如果($count<$limit){ $replace; }否则{ ${^MATCH}; } }xegp;

很遗憾你不能这么做,但你不能: 如果$count>=$limit,则为最后一个;

我的$i(0..3)
是perl编写它的方法。一种更漂亮的方法是
$aa=~s/aa/bb/for 1..3
。可能将
放在最后,除非$aa=~…
放在那里以提高效率请注意,这种方法对于某些搜索和替换表达式对可能会失败,例如
$aa=~s/aa/ba/;
+1指出
s/../for 1..N的问题
。但是这个例子有一个小缺陷,
aaaa
会变成
bbba
而不是
bbbb
@Qtax,谢谢。我不想投休伯特·舍尔纳斯特的反对票,因为他是新来的,他的答案实际上适用于所问的特定问题,但我怀疑OP是否真的适用于
aa
bb
。所以我讨论了他的原因解决方案在这里是脆弱的。@ikegami我已经很久没有使用perl了,但是如果您能够跟踪您在字符串中的位置并从那里重新启动正则表达式搜索,它将解决
s/../../../for 1..N
的问题。虽然这会有点难看。@jb.,添加了这样一个解决方案,但也没有那么漂亮。 my $count = 0; $string =~ s{ $pattern } { $count++; if ($count < $limit ) { $replace; } else { $&; # faking a no-op, replacing with the original match. } }xeg; $string =~ s{ $pattern } { $count++; if ($count < $limit ) { $replace; } else { ${^MATCH}; } }xegp; last if $count >= $limit;