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

I have a problem with missing captured strings in a script supposed to parse the output of the mysqlbinlog tool:
my $comment = '^(\/\*.*\*\/\;)(.*)'; [...] while ($statement !~ m{$comment}s) { $statement .= <$file> or die "Pre +mature EOF.\n"; } print "Found type 1 comment: $1\n";
Executing this code always produces:
Use of uninitialized value in concatenation (.) or string at ./test.pl + line 16, <$file> line 1. Found type 1 comment:

For the line containing the print statement, meaning that $1 is not defined. But I don't understand how that could be. If the regular expression matched there should be something captured, and if not the line wouldn't even be executed...

I tried to reformulate this as while (!($statement =~ m{$comment}s)) but that didn't help either. Could anyone tell me, why nothing's captured here?

Replies are listed 'Best First'.
Re: Capture not working
by ikegami (Patriarch) on Jan 08, 2009 at 13:26 UTC
    $1 and family are implicitly declaredlocalized in the scope in which they reside. In this case, the scope created by while.
    'a'=~/(.)/; print("$1\n"); # a while ( 'b'=~/(.)/ ) { print("$1\n"), # b last; } print("$1\n"); # a

    So don't use $1.

    my $comment_re = qr{/\*.*?\*/;}s; my ($comment, $rest); while (!( ($comment, $rest) = $statement =~ m{^($comment_re)(.*)}s )) +{ defined( my $line = <$file> ) or die "Premature EOF.\n"; $statement .= $line; } print("Found type 1 comment: $comment\n");

    Also fixed .*.*?
    Also fixed buggy premature EOF test.

Re: Capture not working
by cdarke (Prior) on Jan 08, 2009 at 13:35 UTC
    I don't think this has anything to do with captures.

    The error message seems to report an unitialised value in the string concatenation, which means that <$file> is returning undef. So why is your die not working? Try changing the low precedence operator or to ||.


    update: Yep, I'm wrong again.
      If you're unsure where the warning comes from, just run it through perl-5.10:
      mlenz@wvbh074:~$ cat test.pl use strict; use warnings; my $comment = ''; my $statement = ''; while ($statement !~ m{^(/\*.*\*/;)(.*)}s) { $statement .= <DATA> or d +ie "Premature EOF\n"; } print "Found type 1 comment: $1\n"; __DATA__ /* foo */; stuff; mlenz@wvbh074:~$ perl test.pl Use of uninitialized value $1 in concatenation (.) or string at test.p +l line 6, <DATA> line 1. Found type 1 comment:

      Here it tells you uninitialized value $1 explicitly.

      I beg to differ ...uh agree with the OP

      >perl -wle"while ('a'=~/(.)/, 0) {} print(qq{Found $1})" Use of uninitialized value in concatenation (.) or string at -e line 1 +. Found

      Turns out $x .= <> doesn't even cause a warning at EOF?!

      >perl -we"our $x; $x .= <>" <nul >

        Thank you, that's very helpful. I didn't know you can assign the results of a pattern operation to a list like this.

        I don't quite see in how far the EOF test was buggy though, since the data can neither contain blank lines nor lines containing nothing but a "0"...

      Indeed, the or die statement is not working, as it checks that $statement .= <$file> is not a false value, which it will be in most cases..

      Worng answer - see the answers of people actually testing their responses :)