2015-05-15 2 views
1

Как я могу заменить только совпадающий шаблон и вернуть его в одну переменную с помощью Perl?Заменить только в согласованной части шаблона Perl

Например:

my $str = "a.b.AA pat1 BB hgf AA pat1 BB jkl CC pat1 don't change pat1"; 

Я хочу, чтобы соответствовать pat1 между AA и BB и заменить его с оригинальной строки pat2. Тем не менее, я не хочу, чтобы заменить pat1 где-нибудь еще в том же строке

Ожидаемый результат строка:

a.b.AA PAT2 BB hgf AA PAT2 BB jkl CC pat1 don't change pat1 

Я уверен, что должен быть какой-то хороший способ сделать это; пожалуйста, порекомендуйте.

Оригинальная строка:

my $ORG_str = 'A.B.C.\\valid.A .\\valid.A.B.C .\\valid.X.Y.Z .p.q.r.s'; 

Ожидаемое Строка:

my $EXP_op = 'A.B.C.\\valid?A .\\valid?A?B?C .\\valid?X?Y?Z .p.q.r.s'; 

Заменитель характер . к ? только если он находится между обратной косой черты \ и пробельных .

+0

Использование групп захвата является самым простым. –

+1

Ваш исходный сценарий мог бы быть лучше показан '' xxAA pat1 yy pat1 zz BB abc AA pp pat1 qq pat1 rr pat1 ssBB def pat1 ghi pat1 "или что-то в этом роде.Показывая, что множественные появления «pat1» могут появляться между пограничными маркерами AA и BB, наряду с другими символами, помогли бы прояснить проблему. –

+0

Думаю, я убрал сообщение. Но ответ на весь вопрос - это именно то, что делает оператор замещения. Я думаю, что лучший вопрос: «Как сохранить части совпадающего шаблона». Поскольку он сохраняет материал с обеих сторон, мы не можем использовать '\ K'. :( –

ответ

1

Не очень просто с помощью одного регулярного выражения, так что я использовал разделяй и властвуй, чтобы вычислить результат. Это небольшая рекурсивная функция, которая заменяет один «.». в группу ('\' ' «)

Итерация заканчивается, когда нет ничего, чтобы заменить

sub replace { 
    my ($input) = @_; 

    my $result = $input; 
    $result =~ s/(\\\S*?)\.(.*?)/$1?$2/g; 
    return $result if $result eq $input; 
    return replace($result); 
} 

функции с некоторыми тестами

use strict; 

my $ORG_str= 'A.B.C.\\\\valid.A .\\\\valid.A.B.C .\\\\valid.X.Y.Z .p.q.r.s'; 
my $EXP_op ='A.B.C.\\\\valid?A .\\\\valid?A?B?C .\\\\valid?X?Y?Z .p.q.r.s'; 

sub replace { 
    my ($input) = @_; 

    my $result = $input; 
    $result =~ s/(\\\S*?)\.(.*?)/$1?$2/g; 
    return $result if $result eq $input; 
    return replace($result); 
} 

my $check; 
my $result; 
my $expected; 

$check = 'abcd'; $expected = $check; 
$result = replace($check); 
assert($result eq $expected, "'$check' gives '$expected'"); 

$check = 'ab\xxx. cd'; $expected = 'ab\xxx? cd'; 
$result = replace($check); 
assert($result eq $expected, "'$check' gives '$expected'"); 

$check = 'ab\x.x.x. cd'; $expected = 'ab\x?x?x? cd'; 
$result = replace($check); 
assert($result eq $expected, "'$check' gives '$expected'"); 

$check = 'ab\x.x.x. cd\y.y.y.'; $expected = 'ab\x?x?x? cd\y.y.y.'; 
$result = replace($check); 
assert($result eq $expected, "'$check' gives '$expected'"); 

$check = 'ab\x.x.x. cd\xxx.xxx..xxx...x \y.y.y.'; $expected = 'ab\x?x?x? cd\xxx?xxx??xxx???x \y.y.y.'; 
$result = replace($check); 
assert($result eq $expected, "'$check' gives '$expected'"); 

$check = '. ..\.. ...\.. ...\.. ...\..'; $expected = '. ..\?? ...\?? ...\?? ...\..'; 
$result = replace($check); 
assert($result eq $expected, "'$check' gives '$expected'"); 


$check = $ORG_str; $expected = $EXP_op; 
$result = replace($check); 
assert($result eq $expected, "'$check' gives '$expected'"); 


sub assert { 
    my ($cond, $mesg) = @_; 
    print "checking $mesg ... "; 
    die "\nFAIL: $mesg" unless $cond; 
    print "OK\n"; 
} 

Результатом

checking 'abcd' gives 'abcd' ... OK 
checking 'ab\xxx. cd' gives 'ab\xxx? cd' ... OK 
checking 'ab\x.x.x. cd' gives 'ab\x?x?x? cd' ... OK 
checking 'ab\x.x.x. cd\y.y.y.' gives 'ab\x?x?x? cd\y.y.y.' ... OK 
checking 'ab\x.x.x. cd\xxx.xxx..xxx...x \y.y.y.' gives 'ab\x?x?x? cd\xxx?xxx??xxx???x \y.y.y.' ... OK 
checking '. ..\.. ...\.. ...\.. ...\..' gives '. ..\?? ...\?? ...\?? ...\..' ... OK 
checking 'A.B.C.\\valid.A .\\valid.A.B.C .\\valid.X.Y.Z .p.q.r.s' gives 'A.B.C.\\valid?A .\\valid?A?B?C .\\valid?X?Y?Z .p.q.r.s' ... OK 
+0

старый ответ удален;) – Xtof

3

Посмотрите на look-around regexes.

s/(?<=AA)pat1(?= BB)/pat2/g 

Это соответствует и заменяет pat1 окруженный AA и BB.

1
\\\\[^. ]*\K|(?!^)\G\.([^. ]*) 

Вы можете попробовать this.Replace на ?$1 .Увидь демо.

https://regex101.com/r/mT0iE7/28

Результирующая строка не будет точно такой же, как вы хотите, но вы можете легко сделать чистую вверх.

\?(?=\?) 

Заменить empty string и у вас есть то, что вы want.See демо.

https://regex101.com/r/mT0iE7/29

Смежные вопросы