How do I take multiple notes using Perl?

I have Perl code:

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

      

I want to replace each with a +

space and dog

with cat

.

I have this regex:

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

      

But it only matches the first occurrence +

and the last one dog

.

+2


a source to share


7 replies


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

.

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

      



If $1

true, it means matching \+

, so it replaces space; otherwise, it replaces "cat".

+6


a source


Two regular expressions can make your life a lot easier:

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

      



The next matches are "+" followed by a bunch of things and then "dog". Also, "+" is technically a metacharacter.

/+(.*)dog/

      

+8


a source


Simple answer - use 2 lines !:

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

      

Perhaps it can be done on one line with a "non-living" match, but that should do the trick

+4


a source


A hash can 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";

      

I see in the comments that you are interested in performance, the two regex solutions are more performant. This is because any solution that works for a single regex will have to use captures (which slow down the regex).

Below are the test results:

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 test:

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


a source


Perl 5.14 and newer has a non-destructive chaining capability so you can kill 3 birds with one stone: do your two globals and assign the result to a new variable without changing the 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; 

      

Replace all of yours with a +

space and replace each dog

with cat

, assigning the result to a new variable. In one line space.

+3


a source


If speed is important, you should probably stick to two lines. But when I need to do multiple substitutions at once, I usually care more about convenience, so I use the hash as suggested by Hour. Owens. Two advantages over the two-line layer are that it is easy to modify and behaves as expected (for example, replacing "cat" for "dog" and "dog" for "cat" at the same time).

However, I am very lazy to write the regex by hand and prefer to collect it with a join, and use a map to remove 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";

      

+1


a source


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; $_};

      

0


a source







All Articles