我有一个字符串:
$mystring = "My cat likes to eat tomatoes.";
我想做这个字符串的正则表达式2层的替代品。 我想要做的s/cat/dog/
和s/tomatoes/pasta/
。 不过,我不知道如何正确格式化的正则表达式做多的替代品在一个表达,在同一行,在一个声明。 现在,我的一切是:
$mystring =~ s/cat/dog/ig;
$mystring =~ s/tomatoes/pasta/ig;
我有一个字符串:
$mystring = "My cat likes to eat tomatoes.";
我想做这个字符串的正则表达式2层的替代品。 我想要做的s/cat/dog/
和s/tomatoes/pasta/
。 不过,我不知道如何正确格式化的正则表达式做多的替代品在一个表达,在同一行,在一个声明。 现在,我的一切是:
$mystring =~ s/cat/dog/ig;
$mystring =~ s/tomatoes/pasta/ig;
我的建议是你这样做
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;
与往常一样,使用散列为查找表,匹配键,其值替换:
#!/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;
}
你为什么要?
我知道一些的Perl-ERS引以为豪的是能够写出一些最混淆代码想象(看到一些关于这里的代码高尔夫球题),但这并不使它成为一个聪明的做法。
保持它的可读性,只要保持这样你会感谢自己的长远。
编辑:
当然,如果你正在寻找5层或更多的替代品,请(在上帝的母亲)使用某种类型的查找表。 但不要试图写一个巨大的正则表达式,做这一切。
如果你正在寻找的东西是正则表达式本身,直接查找表的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.
在一个单行进行多重替换的一个非常基本的方法是与分组匹配文本。 这会不会让你找到“猫”的所有实例,并与“狗”取代它,但它会带你到“我的狗喜欢吃面食”
$mystring =~ s/(.*)cat(.*)tomatoes(.*)/$1dog$2pasta$3/g;
你可以这样做的快速和肮脏的方式,或快速和清洁方式:
在这两种情况下,你需要一个散列word => replacement
“|”随着快速和肮脏的方式,然后你通过用加入哈希键建立替代的左侧部分。 为了应对重叠词(如“猫”和“catogan”),您需要先放置最长的选项,做一个sort reverse
散列的键。 您仍然可以不与词元字符处理来代替(如“猫++”)。
快速和清洁的方式使用正则表达式::组装构建正则表达式的左侧部分。 它与叠词本身的交易,它是简单的把它处理的字样元字符来代替。
一旦你的字代替,然后你在散列中的相应条目替换它。
下面是一些代码,显示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;
}