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

My code:
if ($macs[1] =~ /(\S{17})\|(\S{17})/) { print "$macs[0] MAC1: $1\n"; print "$macs[0] MAC2: $2\n"; $mac1 = $1; $mac1 =~ s/:/-/g; $mac2 = $2; $mac2 =~ s/:/-/g; #line 65 print "Converted Mac1: $mac1 Mac2: $mac2\n"; #line 66 }
And the output:
ESO13 MAC1: 00:60:16:5D:4D:B4 ESO13 MAC2: 00:60:16:5D:4D:B5 Use of uninitialized value $mac2 in substitution (s///) at ipcheck.pl +line 65, <STDIN> line 1. Use of uninitialized value $mac2 in concatenation (.) or string at ipc +heck.pl line 66, <STDIN> Converted Mac1: 00-60-16-5D-4D-B4 Mac2:

For some reason $2 is uninitialized the second time I try to use it. The same exact code for $1 works. Any ideas why this might be happening? Any help is greatly appreciated!

Replies are listed 'Best First'.
Re: Can anyone tell me what is going on with my code?(Regex match variables)
by Laurent_R (Canon) on Sep 30, 2015 at 17:49 UTC
    Try to put the following line:
    $mac2 = $2;
    before the substitution on $mac1.

    I.e.:

    if ($macs[1] =~ /(\S{17})\|(\S{17})/) { print "$macs[0] MAC1: $1\n"; print "$macs[0] MAC2: $2\n"; $mac1 = $1; $mac2 = $2; $mac1 =~ s/:/-/g; $mac2 =~ s/:/-/g; print "Converted Mac1: $mac1 Mac2: $mac2\n"; }
    The substitution:
    $mac1 =~ s/:/-/g;
    which is a new regex, is basically clearing $2 and making it undefined.

    update: fixed two missing characters while copying and pasting the original code to change it. Thanks to AnomalousMonk for pointing out.

Re: Can anyone tell me what is going on with my code?(Regex match variables)
by Corion (Patriarch) on Sep 30, 2015 at 17:42 UTC

    What do you expect the values of $1 and $2 to be after this line:

    s/:/-/g

    You will need to copy the values before doing another regular expression match.

      If you look in the output I'm expecting all :'s to be replaced with -'s. This worked for $mac1 but not for $mac2. Not sure what you mean by I'll need to copy the value(especially when I didn't need to for the first variable?). Thanks for looking into this.
        $2 is undefined when you assign it to $mac2 because you ran another regex in between, and that regex cleared $2. Assign $2 to $mac2 before the substitution, and it will work OK.
Re: Can anyone tell me what is going on with my code?(Regex match variables)
by kcott (Archbishop) on Sep 30, 2015 at 18:02 UTC

    G'day samh785,

    The special variables $1, $2, etc. are reinitialized on each match. This includes matches done as part of a substitution. After '$mac1 =~ s/:/-/g;', which contains no captures, both $1 and $2 are uninitialized.

    Here's a example:

    #!/usr/bin/env perl -l use strict; use warnings; my $string = 'abc|def'; if ($string =~ /(\S{3})\|(\S{3})/) { print "After first match (in if condition): \$1=$1 \$2=$2"; my $whatever = 'blah'; $whatever =~ s/b/c/; print "After second match (in substitution): \$1=$1 \$2=$2"; }

    Output:

    After first match (in if condition): $1=abc $2=def Use of uninitialized value $1 in concatenation (.) or string at ./pm_1 +143443_match_vars.pl line 12. Use of uninitialized value $2 in concatenation (.) or string at ./pm_1 +143443_match_vars.pl line 12. After second match (in substitution): $1= $2=

    Assigning $2 to $mac2 before attempting the substitution should fix your problem.

    — Ken

      Makes sense and that fixed my issue. Thanks! A little upset that I forgot substituting would reset my values... :'(

        I find it's good practice to "capture" your capture variables immediately after a match even when you know for sure you will never be doing any further regex matching within that scope:

        if ($macs[1] =~ /(\S{17})\|(\S{17})/) { my ($mac1, $mac2) = ($1, $2); ... $mac1 =~ s/.../etc/g; $mac2 =~ s/as/needed/g; ... do_something_with($mac1, $mac2); ... }
        Just make this same, silly mistake as many times as I have and you'll never do otherwise!


        Give a man a fish:  <%-{-{-{-<

        Just a thought. Since you are only switching one character you could use y/// or tr/// instead of s/// and you would not overwrite your match/capture variables. Like: tr/:/-/.

        Ron