Perl: регулярное выражение для условной замены? - PullRequest
2 голосов
/ 11 июля 2019

в этой строке

ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<

Я хочу заменить каждую подстроку между XY и < на ОДИН или ДВА в зависимости от символов в предыдущих скобках:

, если XY после (CN) заменить подстроку на ONE

, если XY после (CI) заменить подстроку на TWO

Таким образом, результат должен быть:

ab<(CN)cdONE<(CI)efgTWO<(CN)zONE<(CI)efgTWO<

XY и следующие символы должны быть заменены, но не угловая скобка <.

Это предназначено для изменения HTML, и произвольные символы могут встречаться между XY и <.Я думаю, мне нужно два регулярных выражения для (CN) и (CI).

# This one replaces just all XY:   
my $s = 'ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<';
$s =~ s/(XY(.*?))</ONE/g;    
# But how to add the conditions to the regex?

Ответы [ 3 ]

8 голосов
/ 11 июля 2019

Вам не нужно два регулярных выражения.Захватите C[NI] и получите соответствующее значение замены из хеша:

#!/usr/bin/perl
use warnings;
use strict;

my $s = 'ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<';

my %replace = (CN => 'ONE', CI => 'TWO');

$s =~ s/(\((C[NI])\).*?)XY.*?</$1$replace{$2}</g;

my $exp = 'ab<(CN)cdONE<(CI)efgTWO<(CN)zONE<(CI)efgTWO<';

use Test::More tests => 1;
is $s, $exp;
2 голосов
/ 11 июля 2019

Я предполагаю, что это выражение или, возможно, измененная версия этого могут работать, хотя и не уверен:

([a-z]{2}<\([A-Z]{2}\)[a-z]{2})([^<]+)(<\([A-Z]{2}\)[a-z]{3})([^<]+)(<\([A-Z]{2}\)[a-z])([^<]+)(<\([A-Z]{2}\)[a-z]{3})([^<]+)<

Test

use strict;
use warnings;

my $str = 'ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<';
my $regex = qr/([a-z]{2}<\([A-Z]{2}\)[a-z]{2})([^<]+)(<\([A-Z]{2}\)[a-z]{3})([^<]+)(<\([A-Z]{2}\)[a-z])([^<]+)(<\([A-Z]{2}\)[a-z]{3})([^<]+)</mp;
my $subst = '"$1ONE$3TWO$5ONE$7TWO<"';

my $result = $str =~ s/$regex/$subst/rgee;

print $result;

Выражение объяснено на верхней правой панели этой демонстрации , если вы хотите изучить / упростить / изменить его, а в этой ссылке вы можете посмотреть, как оно будет если хотите, сравнивайте с некоторыми примерами входных данных шаг за шагом.

1 голос
/ 12 июля 2019

Это можно сделать в регулярном выражении в одну строку, используя /e и троичный оператор ? в /replace/. Опция /r возвращает результирующую строку, фактически исходная строка $s остается неизменной.

use strict;
use warnings;

my $s ='ab<(CN)cdXYlm<(CI)efgXYop<(CN)zXYklmn<(CI)efgXYuvw<';
print (($s=~s/\(([^)]+)\)([^(]+)XY[^(]+</"($1)$2".(($1 eq CN)?ONE:TWO)."<"/gre)."\n");

Выход:

ab<(CN)cdONE<(CI)efgTWO<(CN)zONE<(CI)efgTWO<
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...