我有一个字符串:
$mystring = "My cat likes to eat tomatoes.";
我想用regex对这个字符串进行两次替换。我想s/cat/dog/
和s/tomatoes/pasta/
。但是,我不知道如何正确格式化正则表达式,在一个表达式中,在一个声明中,在一个表达式中执行多个替换。现在,我只有:
$mystring =~ s/cat/dog/ig;
$mystring =~ s/tomatoes/pasta/ig;
答案 0 :(得分:15)
像往常一样,使用哈希作为查找表,匹配键,替换为值:
#!/usr/bin/perl
use strict;
use warnings;
use Regex::PreSuf;
my %repl = (
cat => 'dog',
tomatoes => 'pasta',
);
my $string = "My cat likes to eat tomatoes.";
my $re = presuf( keys %repl );
$string =~ s/($re)/$repl{$1}/ig;
print $string, "\n";
输出:
C:\Temp> t My dog likes to eat pasta.
你也可以使用循环:
for my $k ( keys %repl ) {
$string =~ s/\Q$k/$repl{$k}/ig;
}
答案 1 :(得分:6)
你为什么要这样?
我知道一些Perl-ers为能够编写一些可以想象的最混淆的代码而感到自豪(参见这里的一些代码高尔夫问题),但这并不是一件明智的事情。< / p>
保持可读性,并保持这样,从长远来看,你会感谢自己。
编辑:
当然,如果你正在寻找5个或更多的替代品,请(对于上帝的母亲)使用某种查找表。但是,不要试图编写一个能够完成所有工作的大规模正则表达式。
答案 2 :(得分:3)
如果您正在寻找的东西本身就是正则表达式,那么perl@SinanÜnür的直接查找表将不起作用(因为字符串相等123 eq '\d+'
失败)。
您可以使用Regexp::Assemble
来解决此限制:
use strict;
use warnings;
use Regexp::Assemble;
my %replace = (
'cat' => 'dog',
'(?:tom|pot)atoes' => 'pasta',
);
my $re = Regexp::Assemble->new->track(1)->add(keys %replace);
my $str = 'My cat likes to eat tomatoes.';
while (my $m = $re->match($str)) {
$str =~ s/$m/$replace{$m}/;
}
print $str, $/;
$str = 'My cat likes to eat potatoes.';
while (my $m = $re->match($str)) {
$str =~ s/$m/$replace{$m}/;
}
print $str, $/;
这两个块都产生My dog likes to eat pasta.
答案 3 :(得分:2)
我建议你这样做
my $text = 'My cat likes to eat tomatoes.';
my ( $format = $text ) =~ s/\b(cat|tomatoes)\b/%s/g;
然后你可以这样做:
my $new_sentence = sprintf( $format, 'dog', 'pasta' );
以及:
$new_sentence = sprintf( $format, 'tiger', 'asparagus' );
我和其他人一起去。你不应该想要在一个表达式或一行中完成所有操作......但这是一种方式:
$text =~ s/\b(cat|tomatoes)\b/ ${{ qw<cat dog tomatoes pasta> }}{$1} /ge;
答案 4 :(得分:1)
在一行中执行多个替换的一种非常基本方法是将文本与分组匹配。这将不允许您找到所有“猫”的实例并将其替换为“狗”,但它会让您“我的狗喜欢吃意大利面”
$mystring =~ s/(.*)cat(.*)tomatoes(.*)/$1dog$2pasta$3/g;
答案 5 :(得分:1)
你可以快速而肮脏的方式,或者快速而干净的方式:
在这两种情况下,您都需要哈希word => replacement
使用快速而肮脏的方式,然后通过使用“|”连接哈希的键来构建替换的左侧部分。为了处理重叠的单词(例如'cat'和'catogan'),你需要先放置最长的选项,方法是在哈希的键上做sort reverse
。你仍然无法处理要替换的单词中的元字符(例如'cat ++')。
快速而干净的方式使用Regexp::Assemble构建正则表达式的左侧部分。它本身处理重叠的单词,并且很容易让它处理要替换的单词中的元字符。
一旦有了要替换的单词,就可以用散列中的相应条目替换它。
下面是一些显示2种方法的代码,处理各种情况:
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 6;
use Regexp::Assemble;
my $mystring = "My cat likes to eat tomatoes.";
my $expected = "My dog likes to eat pasta.";
my $repl;
# simple case
$repl= { 'cat' => 'dog', 'tomatoes' => 'pasta', };
is(
repl_simple($mystring, $repl),
$expected,
'look Ma, no module (simple)'
);
my $re= regexp_assemble($repl);
is(
repl_assemble($mystring, $re),
$expected,
'with Regex::Assemble (simple)'
);
# words overlap
$mystring = "My cat (catogan) likes to eat tomatoes.";
$expected = "My dog (doggie) likes to eat pasta.";
$repl= {'cat' => 'dog', 'tomatoes' => 'pasta', 'catogan' => 'doggie', };
is(
repl_simple($mystring, $repl),
$expected,
'no module, words overlap'
);
$re= regexp_assemble( $repl);
is(
repl_assemble($mystring, $re),
$expected,
'with Regex::Assemble, words overlap'
);
# words to replace include meta-characters
$mystring = "My cat (felines++) likes to eat tomatoes.";
$expected = "My dog (wolves--) likes to eat pasta.";
$repl= {'cat' => 'dog', 'tomatoes' => 'pasta', 'felines++' => 'wolves--', };
is(
repl_simple($mystring, $repl),
$expected,
'no module, meta-characters in expression'
);
$re= regexp_assemble( $repl);
is(
repl_assemble($mystring, $re),
$expected,
'with Regex::Assemble, meta-characters in expression'
);
sub repl_simple {
my( $string, $repl)= @_;
my $alternative= join( '|', reverse sort keys %$repl);
$string=~ s{($alternative)}{$repl->{$1}}ig;
return $string;
}
sub regexp_assemble {
my( $repl)= @_;
my $ra = Regexp::Assemble->new;
foreach my $alt (keys %$repl)
{ $ra->add( '\Q' . $alt . '\E'); }
return $ra->re;
}
sub repl_assemble {
my( $string, $re)= @_;
$string=~ s{($re)}{$repl->{$1}}ig;
return $string;
}