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

3

我想在一个字符串中查找所有出现的"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"


1
如果你替换第一个 BBB,你会得到 ADBC,那么“另一个” BBB 在哪里?我不明白... - Fredrik Pihl
@Fredrik- 第一个是A_BBB_BC,另一个是AB_BBB_C。我想用所有可能的结果(在这种情况下是两个)创建一个数组。 - Andy
1
你想要 ABBBBCBBBBE 的输出是什么? - ysth
2个回答

4
为了获得重叠的匹配,您需要使用 Perl 的 pos 运算符进行调整。

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

pos 直接访问正则表达式引擎用于存储偏移量的位置,因此将值赋给 pos 将更改该偏移量,并影响正则表达式中的 \G 零宽断言。这两个效果都会在下一次匹配中发生,因此您不能在当前匹配中使用 pos 影响位置,例如在 (?{pos() = 5})s//pos() = 5/e 中。

设置 pos 还会重置零长度匹配标志,在 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]

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接