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

N00bie alert

I've tried to use the following expression:
if ($string =~ m/(p1)(p2)(p3)/) { rest of block
which captures p1 into $1 p2 into $2 and p3 into $3 as I expect it should.
the question is this: when I try to substitute:
($new1 = $1) =~ s/this/that/;
($new2 = $2) =~ s/this2/that2/;
($new3 = $3) =~ s/this3/that3/;  (and so on)
I get a runtime error (uninitialized value) even though, for the exact same $string and m// when I split the expression into:

$new1 = $1;
$new2 = $2;
$new3 = $3;
$new1 =~ s/this/that/;
$new2 =~ s/this2/that2/;
$new3 =~ s/this3/that3/;
I don't get a runtime error (undefined or other).

I didn't think I was modifying $1 ($2 or $3) so thought the initial substitution should work. I'm wondering what I missed in this case.

thanks in advance

Replies are listed 'Best First'.
Re: modifying en passant
by almut (Canon) on Jan 09, 2010 at 22:47 UTC

    As soon as a s/// matches, the capture buffers are being reset (even if there are no captures in the pattern):

    use strict; use warnings; my $string = "p1p2p3"; if ($string =~ m/(p1)(p2)(p3)/) { print "1: $1 $2 $3\n"; my $whatever = "Foo"; $whatever =~ s/foo/bar/; # no match print "2: $1 $2 $3\n"; # $1 etc. of the first match still avail +able $whatever = "foo"; $whatever =~ s/foo/bar/; # match print "3: $1 $2 $3\n"; # "Use of uninitialized value..." }

      Ahha. I didn't know that, but it tracks to the behavior I've seen in my code. many thanks for the explanation.

Re: modifying en passant
by chromatic (Archbishop) on Jan 09, 2010 at 22:35 UTC
    ($new1 = $1) =~ s/this/that/; ($new2 = $2) =~ s/this2/that2/;

    What do you expect $2 to contain after the first line I quoted here completes?

Re: modifying en passant
by ikegami (Patriarch) on Jan 10, 2010 at 08:48 UTC

    The solution is to copy the captures earlier. One way:

    if ( my ($new1, $new2, $new3) = $string =~ /(p1)(p2)(p3)/ ) { $new1 =~ s/this/that/; $new2 =~ s/this2/that2/; $new3 =~ s/this3/that3/; ... }

    Bonus: No global vars!

      that's a very nice way to do what I intended. hadn't occurred to me to do it that way, but now that I know, I'll use it. thanks

Re: modifying en passant
by sflitman (Hermit) on Jan 09, 2010 at 22:39 UTC
    I'm convinced that you're upsetting the parser with the lvalue expression ($new1=$1), since =~ needs not just an lvalue but a scalar to operate on. Probably best to just use $new=~s/this/that/;

    HTH,
    SSF

      Allow me to convince you otherwise:

      use strict; use warnings; my $valueToKeep = 'wibble'; (my $editedValue = $valueToKeep) =~ s/w/W/g; print "Edited: $editedValue Original: $valueToKeep\n";

      Prints:

      Edited: Wibble Original: wibble

      True laziness is hard work