简体   繁体   English

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

[英]How do I perform multiple replacements with Perl?

I have Perl code: 我有Perl代码:

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

I want to replace every + with space and dog with cat . 我想用cat替换每个+空间和dog

I have this regular expression: 我有这个正则表达式:

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

But, it only matches the first occurrence of + and last dog . 但是,它只匹配第一次出现的+和最后dog

Two regular expressions might make your life a lot easier: 两个正则表达式可能会让您的生活更轻松:

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

The following matches "+," followed by a bunch of stuff, followed by "dog." 以下匹配“+”,然后是一堆东西,接着是“狗”。 Also, "+" is technically a metacharacter. 此外,“+”在技术上是一个元字符。

/+(.*)dog/

You can use the 'e' modifier to execute code in the second part of an s/// expression. 您可以使用'e'修饰符在s///表达式的第二部分中执行代码。

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

If $1 is true, that means the \\+ matched, so it substitutes a space; 如果$1为真,那意味着\\+匹配,所以它替换了一个空格; otherwise it substitutes "cat". 否则它代替“猫”。

Simple answer - use 2 lines!: 简单的答案 - 使用2行!:

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

It could probably be done in one line with 'non-greedy' matching, but this should do the trick 它可能在一行中进行'非贪婪'匹配,但这应该可以解决问题

A hash may do what you want: 哈希可以做你想要的:

#!/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";

In the comments I see that you are concerned with performance, the two regex solution is more performant. 在评论中我看到你关注性能,两个正则表达式解决方案更高效。 This is because any solution that works for one regex will need to use captures (which slow down the regex). 这是因为任何适用于一个正则表达式的解决方案都需要使用捕获(这会降低正则表达式)。

Here are the results of a benchmark: 以下是基准测试的结果:

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%   --

I used the following benchmark: 我使用了以下基准:

#!/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;

Perl 5.14 and newer has the ability to chain substitutions with a non-destructive assignment so you can kill 3 birds with one stone: do your two global substitutions plus assign the result to a new variable without modifying your original variable. Perl 5.14和更新版本具有使用非破坏性赋值链接替换的能力,因此您可以一石二鸟:执行两次全局替换并将结果分配给新变量而不修改原始变量。

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

Will replace all your + with space and replace every dog with cat , assigning the result into a new variable. 将替换所有+空间并用cat替换每只dog ,将结果分配给一个新变量。 In a one-liner. 在一个班轮。

If speed is important, you should probably stick with two lines. 如果速度很重要,你应该坚持使用两条线。 But when I need to do multiple substitions at once I usually care more about convenience, so I use a hash like suggested by Chas. 但是,当我需要一次做多个子站时,我通常更关心方便性,所以我使用像Chas建议的哈希。 Owens. 欧文斯。 Two advantages over the two-liner being that it's easy to modify, and it behaves like expected (eg when substituting "cat" for "dog" and "dog" for "cat" at the same time). 与双线程相比,两个优点是它易于修改,并且表现得像预期的那样(例如,同时将“cat”替换为“dog”而将“dog”替换为“cat”)。

However, I am much to lazy to write the regex by hand and prefer to assemble it with join, and use map to escape stuff: 但是,我非常懒于手工编写正则表达式,而更喜欢用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";

I know this is an old thread, but here's a one-liner for Perls earlier than v5.14: 我知道这是一个旧线程,但是这里的Perls比v5.14早一点:

my $s = 'The+quick+brown+fox+jumps+over+the+lazy+dog+that+is+my+dog';
$s = do {local $_ = $s; s/\+/ /g; s/dog/cat/g; $_};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM