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

发布于 2024-08-31 11:30:01 字数 327 浏览 8 评论 0原文

我有 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

I have Perl code:

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.

I have this regular expression:

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

But, it only matches the first occurrence of + and last dog.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

素罗衫 2024-09-07 11:30:01

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

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

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

You can use the 'e' modifier to execute code in the second part of an s/// expression.

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

If $1 is true, that means the \+ matched, so it substitutes a space; otherwise it substitutes "cat".

雨落□心尘 2024-09-07 11:30:01

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; 

将用空格替换所有 + 并将每个 dog 替换为 cat,将结果分配给一个新变量。在单线中。

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.

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. In a one-liner.

默嘫て 2024-09-07 11:30:01

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

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

下面的匹配“+”,后面跟着一堆东西,后面跟着“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/
长梦不多时 2024-09-07 11:30:01

哈希可以做你想要的:

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

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;
夜夜流光相皎洁 2024-09-07 11:30:01

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

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

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

Simple answer - use 2 lines!:

$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

生生不灭 2024-09-07 11:30:01

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

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. Owens. Two advantages over the two-liner being that it's easy to modify, and it behaves like expected (e.g. when substituting "cat" for "dog" and "dog" for "cat" at the same time).

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:

#!/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";
丶情人眼里出诗心の 2024-09-07 11:30:01

我知道这是一个旧线程,但这里是 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; $_};

I know this is an old thread, but here's a one-liner for Perls earlier than 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; $_};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文