10

我有 Perl 代码:

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

我想+用空格dogcat.

我有这个正则表达式:

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

但是,它只匹配+和 last的第一次出现dog

4

7 回答 7

11

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

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

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

于 2010-05-05T02:29:42.533 回答
10

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

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

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

/+(.*)dog/
于 2010-05-05T00:44:07.627 回答
10

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; 

+用空格替换所有你的并将每个替换dogcat,将结果分配给一个新变量。在一班。

于 2017-03-24T19:49:27.063 回答
7

哈希可以做你想做的事:

#!/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;
于 2010-05-05T18:26:07.617 回答
4

简单的答案 - 使用 2 行!:

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

它可能可以通过“非贪婪”匹配在一行中完成,但这应该可以解决问题

于 2010-05-05T00:43:32.460 回答
3

如果速度很重要,您可能应该坚持使用两条线。但是当我需要一次进行多个替换时,我通常更关心便利性,所以我使用 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";
于 2010-05-05T20:14:40.057 回答
3

我知道这是一个旧线程,但这里有一个用于早于 v5.14 的 Perls 的单行代码:

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; $_};
于 2018-05-17T03:16:42.673 回答