EchoAngel has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, I have this text
abc(" 0.123511, 0.074997, 0.103143, 0.153955, +0.260586",\ " 0.068394, 0.082183, 0.110329, 0.16114 +2, 0.267773",\ " 0.081887, 0.095677, 0.123822, 0.17463 +5, 0.281266",\ " 0.111534, 0.125324, 0.153470, 0.20428 +2, 0.310914",\ " 0.165731, 0.179521, 0.207666, 0.25847 +9, 0.365110");
I have created this code
$TEXT =~ s/abc(\D+)([\d\.\-]*)(.*)/values$1GOVALUE$3/g;
I wanted to replace all the numbers with GOVALUE. However it ends up replacing only one value. However, if i repeat my code many times, it ends up replacing all of it. help?

Replies are listed 'Best First'.
Re: Found a bug with Search and Replace command?
by RazorbladeBidet (Friar) on Mar 04, 2005 at 15:59 UTC
    Your (.*) is greedy, so it ends up matching the rest of the line.

    if you want to replace them all, try something like:

    s/([\d\.-]+)/GOVALUE/g (if I'm reading that correctly).

    Of course, if you have decimals you don't want replaced, that will eat them up too :-/
    --------------
    It's sad that a family can be torn apart by such a such a simple thing as a pack of wild dogs
Re: Found a bug with Search and Replace command? (incremental)
by tye (Sage) on Mar 04, 2005 at 17:31 UTC
    #!/usr/bin/perl -w use strict; my $TEXT= do { local $/; <DATA> }; my $result; if( $TEXT =~ /(.*?abc)/g ) { $result= $1; while( $TEXT =~ /\G(\D+)([\d.\-]+)/g ) { $result .= $1 . "GOVALUE"; } $result .= substr( $TEXT, pos($TEXT) ); } print $result; __END__ abc(" 0.123511, 0.074997, 0.103143, 0.153955, +0.260586",\ " 0.068394, 0.082183, 0.110329, 0.16114 +2, 0.267773",\ " 0.081887, 0.095677, 0.123822, 0.17463 +5, 0.281266",\ " 0.111534, 0.125324, 0.153470, 0.20428 +2, 0.310914",\ " 0.165731, 0.179521, 0.207666, 0.25847 +9, 0.365110");

    Makes one wish you could do incremental s///g (like m//g in a scalar context), though we'd need something like an extra option to request such. s///gc or s///G (belg4mit's) anyone? Of course, it would probably be less efficient than the above code (requiring the entire end of the string to be copied/moved multiple times), but it would be less error-prone.

    - tye        

      You know, you can use \G in s///g after doing a //g.
      $TEXT =~ /abc/g; $TEXT =~ s/\G(\D+)([\d\.\-]*)/$1GOVALUE/g;

      Caution: Contents may have been coded under pressure.

        Did you test this? I'm not claiming you are wrong, but my quick test of it showed it not changing anything:

        #!/usr/bin/perl -w use strict; my $TEXT= do { local $/; <DATA> }; if( $TEXT =~ /abc/g ) { $TEXT =~ s/\G(\D+)([\d\.\-]*)­/$1GOVALUE/g; } print $TEXT; __END__ abc(" 0.123511, 0.074997, 0.103143, 0.153955, +0.260586",\ " 0.068394, 0.082183, 0.110329, 0.16114 +2, 0.267773",\ " 0.081887, 0.095677, 0.123822, 0.17463 +5, 0.281266",\ " 0.111534, 0.125324, 0.153470, 0.20428 +2, 0.310914",\ " 0.165731, 0.179521, 0.207666, 0.25847 +9, 0.365110");

        The output was the same as the input.

        - tye        

Re: Found a bug with Search and Replace command?
by Anonymous Monk on Mar 04, 2005 at 16:36 UTC
    Assuming you want to replace all numbers in the text, and not just the numbers between two substrings, I'd use:
    use Regexp::Common; $text =~ s/$RE{num}{decimal}/GOVALUES/g;
Re: Found a bug with Search and Replace command?
by ww (Archbishop) on Mar 04, 2005 at 19:43 UTC
    Argh! This looked straightforward when first looked more than an hour ago. Now would appreciate wisdom from the Monastery (on which, details below). But before we get to that would also appreciate a little clarification from OP, EchoAngel:

    Do you want the entire set of numeric values replaced with a single character string, "GOVALUE?"

    And when you say "repeat my code" do you mean replicating it, in line, with essentially identical code?

    In other words, please help me understand (I see there are others who may have provided the help you wanted) by an example or more precise description of the desired output (and the method of your "repeat my code."

    Following comments reflect my (mis-)understanding, WHICH MAY BE WRONG -- corrections sought!

    s/     start "substitution" -- not exactly "find and replace"
        abc    # match (but don't capture or keep) "abc"
        (\D+)    # capture one_or_more non-digits followed by a space
        ([\d\.\-]*)    # capture (as $2) zero_or_more digits, dots, slashes** or minus-signs (fol by a space)
        (.*)/    # On the data provided, capture (as $3) anything and everything except a newline, starting at the first comma after the first decimal value

    ** or are you trying to escape the hyphen in class? if so, that's not necessary as the first or last element because if its the last thing in a class it can't be a range operator

    and replace the original $text with:
    "values" followed by the non-digits in $1 "(open_paren, dquote)" followed by "GOVALUE" followed by the contents of $3 -- everything not previously captured in $1 or $2.

    interpretation above developed from code; appears to match output
    values(" GOVALUE, 0.074997, 0.103143, 0.153955, 0.260586", " 0.068394, 0.082183, 0.110329, 0.161142, 0.26777 +3", " 0.081887, 0.095677, 0.123822, 0.174635, 0.28126 +6", " 0.111534, 0.125324, 0.153470, 0.204282, 0.31091 +4", " 0.165731, 0.179521, 0.207666, 0.258479, 0.36511 +0")

    ...if your data is qq'ed into the value assigned to $text. ie,

    #!c:/perl/bin -w $text = qq ( abc(" 0.123511, 0.074997, 0.103143, 0.153955, 0.26058 +6",\ " 0.068394, 0.082183, 0.110329, 0.161142, 0.2677 +73",\ " 0.081887, 0.095677, 0.123822, 0.174635, 0.2812 +66",\ " 0.111534, 0.125324, 0.153470, 0.204282, 0.3109 +14",\ " 0.165731, 0.179521, 0.207666, 0.258479, 0.3651 +10") ); $text =~ s/abc(\D+)([\d\.\-]*)(.*)/values$1GOVALUE$3/g; print "$text\n";

    However, while trying to make certain I wasn't mistating (was I?) re escaping a initial or final hyphen in a class, I started playing with variant forms, such as:

    $text2 = 'foo|abc-./|foo '; # $text2 =~ s%(foo|\w+)([//.-]+)(.*)%$1 :i: $2 :i: $3%g; # output is: ++foo|abc :i: -./ :i: |foo ++ # captures the hyphen, dot and slash in $2 with ONLY the fwd_slash esc +aped # and capturs "|foo " in $3 # $text2 =~ s%([\w|]+)([.-]+)(.*)%__$1_:_$2_:_$3__ : second variation% +g; # output is: ++__foo|abc_:_-._:_/|foo __ : second variation++ # hyphen, dot still captured in $2 with no escaping at all inside the +class $text2 =~ s%([\w|]+)([.-]+/)(.*)%$1:$2:$3 : third variation%g; # output is: ++foo|abc:-./:|foo : third variation++ # Moved the fw_slash (unescaped, using % as delimiters) into the secon +d capture # expression... and fw_slash turns up correctly in $2 print "\t++$text2++\n";

    But the alternates above go all around the barn. Any hints, please, on a better way to do a demo on this (narrow) matter?

Re: Found a bug with Search and Replace command?
by Anonymous Monk on Mar 04, 2005 at 23:15 UTC
    Found a bug with Search and Replace command?

    Never wonder that out loud

Re: Found a bug with Search and Replace command?
by sh1tn (Priest) on Mar 04, 2005 at 16:10 UTC
    Maybe you are trying sm.th. like:
    s/(\D+)([\d\.\-]*)/values$1GOVALUE$2/g;