这是我的字符串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
可能是因为我的两种模式中的字符数不同。
有没有办法用其他代码替换不同大小的图案?非常感谢。
答案 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/'