Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

How do I replace a substring (if exists) with a different substring in a string?

by kommesel (Sexton)
on Jul 20, 2001 at 13:44 UTC ( [id://98357]=perlquestion: print w/replies, xml ) Need Help??

kommesel has asked for the wisdom of the Perl Monks concerning the following question: (strings)

How do I replace a substring (if exists) with a different substring in a string?

Originally posted as a Categorized Question.

  • Comment on How do I replace a substring (if exists) with a different substring in a string?

Replies are listed 'Best First'.
Re: How do I replace a substring (if exists) with a different substring in a string?
by tachyon (Chancellor) on Jul 20, 2001 at 15:43 UTC

    You can use a s/// regex like this:

    my $str = "I have a dream"; my $find = "have"; my $replace = "had"; $find = quotemeta $find; # escape regex metachars if present $str =~ s/$find/$replace/g; print $str;

    The quotemeta lets you find strings that contain regex meta characters and the /g at the end of the s/// does all occurances.

    cheers

    tachyon

Re: How do I replace a substring (if exists) with a different substring in a string?
by harangzsolt33 (Chaplain) on Jun 25, 2016 at 18:23 UTC
    Another way to do it is split the string at every occurrence of $find and then join it together using the new pattern $replace like this:
    $string = join( $replace, split($find, $string) );
    I think, this is a much neater way to do it, however I do not know how fast it is or how much more memory it uses. I have found that in JavaScript, this method works faster than the regular replace() method. Generally, working with arrays in JavaScript is always faster than working with strings. Btw could somebody do a benchmark on this to see how it compares to the other solutions?
      Here's the benchmark. It seems changing the lengths of the involved strings heavily influences the results:
      #!/usr/bin/perl use warnings; use strict; use Test::More; use Benchmark qw{ cmpthese }; sub regex { my ($string, $find, $replace) = @_; $string =~ s/\Q$find/$replace/g; $string } sub substring { my ($string, $find, $replace) = @_; my $length = length $find; my $pos = 0; while (-1 != ( $pos = index $string, $find, $pos )) { substr $string, $pos, $length, $replace; } $string } sub array { my ($string, $find, $replace) = @_; join $replace, split /\Q$find/, $string, -1 } my @args = ('12a345a678a90', 'a', '||'); is regex(@args), '12||345||678||90', 'manual'; for my $args (\@args, [ '123456789abcdefghijkl' x 1000, '123456789abcdefghijkl' x 21, 'ABCDEFGH' ]) { is regex(@$args), substring(@$args), 'regex - substring'; is substring(@$args), array(@$args), 'substring - array'; cmpthese(-3, { regex => sub { regex(@$args) }, substring => sub { substring(@$args) }, array => sub { array(@$args) }, }); } done_testing(5);

      Output on my machine (Perl 5.20.1, Linux on Intel i3):

      ok 1 - manual ok 2 - regex - substring ok 3 - substring - array Rate regex substring array regex 313491/s -- -21% -36% substring 398041/s 27% -- -19% array 488419/s 56% 23% -- ok 4 - regex - substring ok 5 - substring - array Rate substring array regex substring 18505/s -- -15% -15% array 21765/s 18% -- -0% regex 21765/s 18% 0% -- 1..5

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,
      I'd add quotemeta to $find as it can contain characters with special meanings in regular expressions.

      ($q=q:Sq=~/;[c](.)(.)/;chr(-||-|5+lengthSq)`"S|oS2"`map{chr |+ord }map{substrSq`S_+|`|}3E|-|`7**2-3:)=~y+S|`+$1,++print+eval$q,q,a,

      I wrote a little program that runs a million string replace operations using the three methods that have been suggested here so far, and it displays how many seconds it takes to run each replace operation. (I am using tinyperl 5.8 on Windows XP Pro SP2. And I am a beginner Perl programmer.)

      As it turns out, if the length of the resulting string is longer than the original after the replacement, then it takes longer to do the replacement. Btw, the regexp has been the fastest method. The split/join method was average. And the substr method was the slowest! It was so slow that I had to abort the program after it replaced 1 million "HelloWorld" strings to "XXWorld." It took more than an hour! Anyway, here is the code:

Re: How do I replace a substring (if exists) with a different substring in a string?
by davorg (Chancellor) on Jul 20, 2001 at 13:50 UTC

    With appropriate use of index, length and substr.

    And remember that substr can be used as an lvalue.

Re: How do I replace a substring (if exists) with a different substring in a string?
by dkubb (Deacon) on Jul 20, 2001 at 22:56 UTC

    You can use substr, length, and index inside a while loop to do what you want:

    my $string = '01234567890'; my $find = '0'; my $replace = 'a'; my $pos = index($string, $find); while($pos > -1) { substr($string, $pos, length($find), $replace); $pos = index($string, $find, $pos + length($replace)); }

    IMHO you can't beat the following for readability:

    $string =~ s/\Q$find\E/$replace/g;

      Note: I found a bug in my earlier answer, since I can't edit it, I am posting this follow up. If the string to replace has the substring you are trying to find, it can get into an endless loop. Here is an updated ansewer:

      my $string = '01234567890'; my $find = '0'; my $replace = 'a'; my $pos = index($string, $find); while($pos > -1) { substr($string, $pos, length($find), $replace); $pos = index($string, $find, $pos + length($replace)); }

      In this case, an s/// regex is actually 5% faster.

      actually you can change:
      substr( $string, $pos, $length( $find ), $replace );
      with this one:
      substr( $created, $pos, length( $find ), $replace );
      $length is not function!!!

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://98357]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others surveying the Monastery: (5)
As of 2024-04-25 11:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found