正则表达式搜索和替换,仅在n次匹配后开始

时间:2012-09-18 20:38:59

标签: regex perl awk

我想搜索并替换一个简单的字符串,仅在每行上有这么多匹配后开始,例如:

s / ZZ / YY,n = 2

xxxZZxxxxxxZZxxxxZZxZZxxxxZZ
xZZxxxZZxxZZxxZZxZZxxxZZxxx
...

成:

xxxZZxxxxxxZZxxxxxYYxxxxYY
xZZxxxZZxxYYxxYYxYYxxxYYxxx
...

在我的问题中,在连续的“ZZ”之间总会有一个'x'。提前谢谢。

4 个答案:

答案 0 :(得分:4)

我建议使用可执行的替换字符串,它允许您计算到目前为止看到的匹配数

此代码演示

use strict;
use warnings;

while (<DATA>) {
  my $n = 0;
  s/(ZZ)/$n++ < 2 ? $1 : 'YY'/eg;
  print;
}

__DATA__
xxxZZxxxxxxZZxxxxZZxZZxxxxZZ
xZZxxxZZxxZZxxZZxZZxxxZZxxx

<强>输出

xxxZZxxxxxxZZxxxxYYxYYxxxxYY
xZZxxxZZxxYYxxYYxYYxxxYYxxx

答案 1 :(得分:3)

可能有后备解决方案,或者反向串行和反向前进和反向再次解决方案(如果有的话,我会支持它们),但我通常会发现使用while的解决方案更容易发现,并且更容易阅读。

1 while $string =~ s/(ZZ.*ZZ.*)ZZ/$1YY/

也就是说,虽然字符串包含三个ZZ模式,但请将第三个模式替换为YY

作为一般解决方案:

$expr = (quotemeta($pattern1) . ".*") x $n;
1 while $string =~ s/($expr)\Q$pattern2\E/$1$pattern2/;

答案 2 :(得分:1)

似乎最简单的perl解决方案1 while s/ZZ/YY/3,但perl不接受。对sed

也一样
sed ':a
  s/ZZ/YY/3
  ta'

sed的某些实现允许更简单地编写:sed ':a; s/ZZ/YY/3; ta',并且我相信它可以完全移植:sed -e :a -e s/ZZ/YY/3 -e ta

答案 3 :(得分:1)

1 while $thisline=~s/((?:x*?ZZx*?){2}[xZY]*?)ZZ/$1YY/;

这是n = 2的解决方案。

您只需更改其他n值的数字。

此外,我使用延迟匹配优化了替换,并消除了多余的捕获。