Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

why such an error happened?

by lightoverhead (Monk)
on Oct 20, 2008 at 00:58 UTC ( #718110=perlquestion: print w/ replies, xml ) Need Help??
lightoverhead has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, I have run several lines of code as below:
#!/usr/bin/perl -w use strict; my $chr; $chr = "this and that"; $chr =~ s/(this|that)|(\w+)/$1\U$2/g; #error reported print "$chr\n";
reuslts:
this AND that

But it reported error message:

Use of uninitialized value in concatenation (.) or string at test.pl line 5.

I don't known why it reported an error at line 5, since $chr was already declared.

Thanks.

Comment on why such an error happened?
Select or Download Code
Re: why such an error happened?
by McDarren (Abbot) on Oct 20, 2008 at 01:08 UTC
    It's not an error, it's a warning.

    And you're getting this warning because $2 is undefined.

    Take a closer look at your regular expression. You only have one set of capturing parentheses on each side of the alternation, so you're only ever going to get one match. ie. $2 will always be undefined.

    Cheers,
    Darren

      Thank you Darren. But I am still confused. $1 is matched to "this" or "that", so they will not be upper cased. $2 matched to other words other than "this" or "that" and change them to upper cases, in this example, the "and" was changed to "AND". It seems to me that the "and" was assigned to $2, why you thought that $2 will always be undefined? Thanks.

        Because of the | in the middle of the regex there will never be a time where both parenthesis are used. That is, there will only be one set of parenthesis total. Ergo, $2 will never be defined.

        I'm so adjective, I verb nouns!

        chomp; # nom nom nom

      You only have one set of capturing parentheses on each side of the alternation, so you're only ever going to get one match. ie. $2 will always be undefined.
      Not true.

      What is true that you get only one defined capture (if there's a match), but that one can very well be $2.

Re: why such an error happened?
by GrandFather (Cardinal) on Oct 20, 2008 at 01:36 UTC

    Only one of the alternates matches for any particular iteration. Because you have two captures in the regex one of them must be undefined for each match. Consider the following debugging version of your regex:

    use strict; my $chr; $chr = "this and that"; $chr =~ s/ (?: (this|that)(?{print "matched lh alt: $1 "}) # Left hand altern +ate | (\w+)(?{print "matched rh alt: $2 "}) # Right hand alter +nate ) (?{print 'def 1' if defined ($1); print 'def 2' if defined ($2); p +rint "\n"}) /$1\U$2/xg; print "$chr\n";

    Prints:

    matched lh alt: this def 1 matched rh alt: and def 2 matched lh alt: that def 1 this AND that

    Note that only one of $1 and $2 are defined for each match.


    Perl reduces RSI - it saves typing
Re: why such an error happened?
by krusty (Hermit) on Oct 20, 2008 at 01:44 UTC
    Your global substitution matches the string you gave it three times.

    The first match only matches "this" and stores it in $1. $2 either contains an empty string or is undefined (I don't know which as it's never mattered to my code).

    The second match doesn't match "this" or "that" so it moves on to one or more word characters and matches "and" and stores it in $2. This time $1 is undef.

    The last match matches "that" and stores it once again in $1. $2 is undef.

    It seems as if you are possibly confused by either the number of times the substitution actually matches or by which portion of the string gets assigned to $1 and $2.

    The reason why you are getting the warning, is that each time the substitution matches, the replacement pattern contains an uninitialized value in $2, $1, and $2 respectively.

    If you are having trouble figuring out which portion of the string would be assigned to $1 and $2, then the following code may help. If you can count left parentheses, you can figure out what part of the string will be assigned to which variable from left to right. For instance the following string will match as follows.
    $string = "A Perl among Camels"; $string =~ /(((\w+) (\w+)) ((\w+) (\w+)))/g; print "1 is '$1'\n 2 is '$2'\n 3 is '$3'\n 4 is '$4'\n 5 is '$5'\n 6 is '$6'\n 7 is '$7'\n";

    returns:
    1 is 'A Perl among Camels' 2 is 'A Perl' 3 is 'A' 4 is 'Perl' 5 is 'among Camels' 6 is 'among' 7 is 'Camels'
Re: why such an error happened?
by pobocks (Chaplain) on Oct 20, 2008 at 05:37 UTC

    I'm not actually sure what you're trying to do here, but I do know what's causing the error.

    What it says right now is Match EITHER (this | that) OR (\w+) -> Any wordlike object including 'this' and 'that' and replace it with the first capture followed by the second capture. Do this globally (i.e. over and over until the whole string is changed).

    The problem is, there's only ever one match. EITHER (this|that) matches, or (\w+) matches. Thus, $2 stays empty, thus uninitialized value.

    while(<DATA>){for(split(' ',$_)){$_=reverse;print "$_ ";}};print "\b.\ +n"; __DATA__ tsuJ rehtonA lreP rekcaH
Re: why such an error happened?
by Anonymous Monk on Oct 20, 2008 at 09:24 UTC
    #!/usr/bin/perl -- use warnings; use strict; use re 'debug'; my $chr = "this and that"; $chr =~ s/(this|that)|(\w+)/$1\U$2/g; #error reported print "$chr\n"; __END__
Re: why such an error happened?
by AnomalousMonk (Monsignor) on Oct 20, 2008 at 14:38 UTC
    I think something else is going on.

    Consider these three examples (note that the example string is different):

    >perl -wMstrict -le "my $chr; $chr = \"x this and that y\"; $chr =~ s/(this|that)|(\w+)/$1\U$2/g; print \"$chr\n\"; " Use of uninitialized value in concatenation (.) or string ... Use of uninitialized value in concatenation (.) or string ... Use of uninitialized value in concatenation (.) or string ... X this AND that Y
    and
    >perl -wMstrict -le "my $chr; $chr = \"x this and that y\"; $chr =~ s/(this|that)|(\w+)/\u$1\E$2/g; print \"$chr\n\"; " Use of uninitialized value in concatenation (.) or string ... Use of uninitialized value in concatenation (.) or string ... x This and That y
    and
    >perl -wMstrict -le "my $chr; $chr = \"x this and that y\"; $chr =~ s/(this|that)|(\w+)/\u$1\E\U$2/g; print \"$chr\n\"; " X This AND That Y
    As mentioned before, either one or the other (but not both) of the capturing groups will be satisfied, so either $1 or $2 (but not both) will be defined. In all the all examples, the regex matches five times, twice for (this|that) and three times for (\w+), but various numbers of warnings are printed.

    The number of warnings depends on which capture variable is defined and which capture variable is 'transformed' by \u or \U in the replacement string. (A replacement string without any \u or \U transformations yields five warnings.)

    When both $1 and $2 are transformed in some way within the replacement string, there are no warnings. Apparently, and surprisingly (to me at any rate), the \u and \U transformations in the replacement string suppress the warnings I expected.

    Offhand, I can't think why this is the case.

    Update: Corrected a swapped word order.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (16)
As of 2014-07-23 15:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite superfluous repetitious redundant duplicative phrase is:









    Results (145 votes), past polls