如何使用Perl执行多个替换?

时间:2010-05-05 00:38:03

标签: regex perl substitution

我有Perl代码:

my $s =  "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";

我想用空格替换每个+,用dog替换cat

我有这个正则表达式:

$s =~ s/\+(.*)dog/ ${1}cat/g;

但是,它仅匹配第一次出现+和最后dog

7 个答案:

答案 0 :(得分:8)

两个正则表达式可能会让您的生活更轻松:

$s =~ s/\+/ /g;
$s =~ s/dog/cat/g;

以下匹配“+”,后跟一堆东西,后跟“狗”。另外,“+”在技术上是一个元字符。

/+(.*)dog/

答案 1 :(得分:6)

您可以使用'e'修饰符在s///表达式的第二部分执行代码。

$s =~ s/(\+)|(dog)/$1 ? ' ' : 'cat'/eg;

如果$1为真,则表示\+匹配,因此它会替换空格;否则它代替“猫”。

答案 2 :(得分:4)

简单回答 - 使用2行!:

$s =~ s/+/ /g;
$s =~ s/dog/cat/g;

它可能在一行中进行'非贪婪'匹配,但这应该可以解决这个问题

答案 3 :(得分:4)

哈希可以做你想做的事:

#!/usr/bin/perl

use strict;
use warnings;

my $s =  "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";

my %replace = (
    "+" => " ",
    dog => "cat",
);

$s =~ s/([+]|dog)/$replace{$1}/g;

print "$s\n";

在评论中我看到你关注性能,这两个正则表达式解决方案更具性能。这是因为任何适用于一个正则表达式的解决方案都需要使用捕获(这会降低正则表达式)。

以下是基准测试的结果:

eval: The quick brown fox jumps over the lazy cat that is my cat
hash: The quick brown fox jumps over the lazy cat that is my cat
two: The quick brown fox jumps over the lazy cat that is my cat
         Rate hash eval  two
hash  33184/s   -- -29% -80%
eval  46419/s  40%   -- -72%
two  165414/s 398% 256%   --

我使用了以下基准:

#!/usr/bin/perl

use strict;
use warnings;

use Benchmark;

my $s =  "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";

my %replace = (
    "+" => " ",
    dog => "cat",
);

my %subs = (
    hash => sub {
        (my $t = $s) =~ s/([+]|dog)/$replace{$1}/g;
        return $t;
    },
    two => sub {
        (my $t = $s) =~ s/[+]/ /g;
        $t =~ s/dog/cat/g;
        return $t;
    },
    eval => sub {
        (my $t = $s) =~ s/(\+)|(dog)/$1 ? ' ' : 'cat'/eg;
        return $t;
    },
);

for my $k (sort keys %subs) {
    print "$k: ", $subs{$k}(), "\n";
}

Benchmark::cmpthese -1, \%subs;

答案 4 :(得分:4)

Perl 5.14和更新版本能够使用非破坏性赋值链接替换,因此您可以一举杀死3只鸟:执行两次全局替换并将结果分配给新变量而不修改原始变量。

my $s =  "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";
my $result = $s =~ s/+/ /gr 
                =~ s/dog/cat/gr; 

+替换为空格,并将每个dog替换为cat,并将结果分配到新变量中。在单行中。

答案 5 :(得分:1)

如果速度很重要,你应该坚持使用两条线。但是,当我需要一次做多个子站时,我通常更关心方便性,所以我使用像Chas建议的哈希。欧文斯。与双线程相比,两个优点是易于修改,并且表现得像预期的那样(例如,同时将“cat”替换为“dog”而将“dog”替换为“cat”)。

但是,我非常懒于手工编写正则表达式,而更喜欢用join来组装它,并使用map来逃避:

#!/usr/bin/perl

use strict;
use warnings;

my $s = "The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog";

my %replace = (
    "+" => " ",
    dog => "cat",
);

my $regex = join "|", 
    #use quotemeta to escape special characters
    map  { quotemeta } 
    #reverse sort the keys because "ab" =~ /(a|ab)/ returns "a"
    sort { $b cmp $a } keys %replace;

#compiling the regex before using it prevents
#you from having to recompile it each time
$regex = qr/$regex/;

$s =~ s/($regex)/$replace{$1}/g;

print "$s\n";

答案 6 :(得分:0)

我知道这是一个老话题,但是这里是Perls早于v5.14的单行代码:

127.0.0.1:3306