如何用Perl正则表达式替换重叠匹配?

时间:2011-07-04 13:30:27

标签: regex perl substitution

我想在字符串中找到"BBB"的所有出现,并用"D"替换它们。例如,我有"ABBBBC"并希望生成"ADBC""ABDC"。 (首先替换第一个BBB,然后替换另一个BBB)。在Perl中有一个很好的方法吗?

$str = "ABBBBC";
for ( $str =~ m/B(?=BB)/g ) {
    # I match both the BBBs here, but how to substitute the relevant part?
}

我想获得这个数组:('ADBC', 'ABDC'),它来自将BBB更改为D。字符串"ABBBBBC"会给我"ADBBC""ABDBC""ABBDC"

2 个答案:

答案 0 :(得分:4)

要获得重叠匹配,您必须使用Perl的pos运算符。

  

<强> pos SCALAR
  的 pos
  返回最后m//g次搜索为所讨论的变量停止的位置的偏移量(未指定变量时使用$_)。请注意,0是有效的匹配偏移量。 undef表示搜索位置已重置(通常是由于匹配失败,但也可能是因为尚未在标量上运行匹配)。

     

pos直接访问regexp引擎用于存储偏移量的位置,因此分配给pos将改变该偏移量,因此也将影响正则表达式中的\G零宽度断言。这两种效果都会在下一场比赛中发生,因此您无法在当前比赛中使用pos影响排名,例如(?{pos() = 5})s//pos() = 5/e

     

设置pos也会重置匹配的零长度标记,在Repeated Patterns Matching a Zero-length Substring in perlre下描述。

     

由于失败的m//gc匹配不会重置偏移量,因此pos的返回值在此情况下也不会更改。请参阅perlreperlop

例如:

#! /usr/bin/env perl

use strict;
use warnings;

my $str = "ABBBBC";
my @replaced;
while ($str =~ m/^(.*)\G(.+?)BBB(.*)$/g ) {
  push @replaced, $1 . $2 . "D" . $3;
  pos($str) = length($1) + 1;
}

print "[", join("][" => @replaced), "]\n";

输出:

$ ./prog
[ADBC][ABDC]

答案 1 :(得分:0)

local our @replaced;
'ABBBBC' =~ /^(.*)BBB(.*)\z(?{ push @replaced, $1.'D'.$2 })(?!)/s;