perl:具有不同尺寸图案的替代图案

时间:2015-06-12 21:40:59

标签: regex perl substitution

这是我的字符串A B C D,我希望将A替换为123,将C替换为456。然而,这不起作用。

$string=~ s/A|B|C|D/123|B|456|D/;

我想要123 B 456 D,但我得到123|B|456|D B C D

可能是因为我的两种模式中的字符数不同。

有没有办法用其他代码替换不同大小的图案?非常感谢。

4 个答案:

答案 0 :(得分:7)

你得到了我期望你得到的东西。您的正则表达式会查找'A''B''C''D'一次次出现,并将其替换为文字字符串 '123|B|456|D'。因此'A B C D' - > '123|B|456|D B C D'

因此它找到第一个匹配项'A'并将其替换为您指定的字符串。 交替匹配各种字符串,但管道字符在替换插槽中没有任何意义。

您需要做的是创建从输入到输出的映射,如下所示:

my %map = ( A => '123', C => '456' );

然后你需要在替换中使用它。让我们给你一个搜索表达式:

my $search = join( '|', keys %map );

现在让我们编写替换(当我编写包含代码的替换时,我更喜欢括号:

$string =~ s{($search)}{ $map{$1} }g;

g开关意味着我们匹配字符串的每个部分,而e开关告诉Perl将评估替换表达式作为Perl代码。

输出为'123 B 456 D'

答案 1 :(得分:2)

使用eval(未经测试)这样的东西。

$string=~ s/(A)|C/ length($1) ? '123': '456'/eg;  

使用s///表单中的 eval 标志表示评估替换
side作为返回值的代码行。

在这种情况下,它在替换代码中执行三元条件。

这有点像内联正则表达式回调 它要复杂得多,因为它可以像s///eeg那样 更好地参考文档。

请记住, eval 非常邪恶,拼写错误!!

答案 2 :(得分:1)

最简单的方法是进行两次替换:

$string =~ s/A/123/g;
$string =~ s/B/456/g;

或甚至(使用内联for循环作为简写,将多个替换应用于一个字符串):

s/A/123/g, s/B/456/g for $string;

当然,对于更复杂的模式,这可能不会产生与在一次传递中进行两次替换相同的结果;特别是,如果模式可以重叠(如A = YZ,B = XY),或者模式B可以匹配替换模式A的字符串,则可能会发生这种情况。

如果您希望一次性完成此操作,最常见的解决方案是使用/e modifier,这会导致替换被解释为Perl代码,如:

$string =~ s/(A|B)/ $1 eq 'A' ? '123' : '456' /eg;

你甚至可以在替换中包含多个以分号分隔的表达式;最后一个表达式的值是将被替换为字符串的值。如果您这样做,您可能会发现使用paired delimiters来提高可读性很有用,例如:

$string =~ s{(A|B)}{
    my $foo = "";
    $foo = '123' if $1 eq 'A';
    $foo = '456' if $1 eq 'B';
    $foo;  # <-- this is what gets substituted for the pattern
}eg;

如果您的模式是常量字符串(如上面的简单示例所示),则更有效的解决方案是使用查找散列,如:

my %map = ('A' => '123', 'B' => '456');
$string =~ s/(A|B)/$map{$1}/g;

使用此方法,您甚至不需要/e修饰符(尽管如此,对于此特定示例,添加它将没有任何区别)。使用/e的优点是,它允许您实现更复杂的规则来选择替换,而不是简单的哈希查找允许。

答案 3 :(得分:0)

String="A B C D"

echo $String | perl - pi - e 's/A/123/' && perl - pi - e 's/C/456/'