Perl:用于条件替换的正则表达式吗?

时间:2019-07-11 15:13:08

标签: regex perl

在此字符串中

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 个答案:

答案 0 :(得分:8)

您不需要两个正则表达式。捕获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;

答案 1 :(得分:2)

我的猜测是该表达式或该表达式的修改版本可能有效,但不确定:

([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})([^<]+)<

测试

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;

this demo的右上角对表达式进行了说明,如果您想探索/简化/修改它,在this link中,您可以观察它如何与某些示例输入步骤匹配一步一步,如果您喜欢。

答案 2 :(得分:1)

这可以使用/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<