Как заменить перекрывающиеся совпадения регулярным выражением Perl? - PullRequest
3 голосов
/ 04 июля 2011

Я хочу найти все вхождения "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 s на D. Строка "ABBBBBC" даст мне "ADBBC", "ABDBC" и "ABBDC".

Ответы [ 2 ]

4 голосов
/ 04 июля 2011

Чтобы получить совпадающие матчи, вы должны поиграть с оператором Perl pos.

pos SCALAR
pos
Возвращает смещение, где был остановлен последний поиск m//g для рассматриваемой переменной ($_ используется, когда переменная не указана).Обратите внимание, что 0 является допустимым смещением совпадения.undef указывает, что позиция поиска сбрасывается (обычно из-за сбоя совпадения, но также может быть связано с тем, что в скаляре еще не найдено совпадений).

pos прямой доступместоположение, используемое механизмом регулярных выражений для хранения смещения, поэтому присвоение pos изменит это смещение, а также повлияет на утверждение \G нулевой ширины в регулярных выражениях.Оба этих эффекта имеют место для следующего матча, поэтому вы не можете повлиять на позицию с pos во время текущего матча, например, в (?{pos() = 5}) или s//pos() = 5/e.

Настройка pos такжесбрасывает флаг совпадения с нулевой длиной, описанный в разделе Повторяющиеся шаблоны, совпадающие с подстрокой нулевой длины в perlre .

Поскольку неудачное совпадение m//gc не сбрасывает смещение, возвращаетсяс pos тоже не изменится в этом случае.См. perlre и perlop .

Например:

#! /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 голосов
/ 04 июля 2011
local our @replaced;
'ABBBBC' =~ /^(.*)BBB(.*)\z(?{ push @replaced, $1.'D'.$2 })(?!)/s;
...