Wiwild
Wiwild

Reputation: 83

Use of uninitialized value $2 in concatenation (.) or string

I transferred my site on another server and this error happened :

PERL : Use of uninitialized value $2 in concatenation (.) or string at /Toolbox.pm line 40.

The function :

36 sub WT_filter{
37 
38    my $filter = sub {
39         my $text_ref = shift;
40         $$text_ref =~ s/\[\%([^ ]+?)( .*)?\%\]/<TMPL_VAR NAME=\"$1\"$2>/g;
41    };
42
43    return $filter;
44
45 } #sub WT_filter

Thanks !

Upvotes: 3

Views: 3587

Answers (3)

doubleud
doubleud

Reputation: 324

The regexp's second parenthesis did not match anything.

It seems that the functions rewrites e.g.: [%something other params%] to: <TMPL_VAR_NAME="something" other params>

It seems that the string must have looked like this: [%something%], which matched only ([^ ]+?) but not ( .*).

Take a look in the file in which this error occurred, you should be able to find the troublesome string.

Upvotes: 1

Robby Cornelissen
Robby Cornelissen

Reputation: 97381

Looking at your regular expression:

\[\%([^ ]+?)( .*)?\%\]

You're trying to extract two groups: ([^ ]+?) and ( .*)?. Note that the second group is followed by a question mark (?), marking it as optional.

Now, let's say you try to match text in which the second optional group is not present, for example [%whatever%]

In this case, the second backreference variable ($2) will not be initialized. If you then try to use that uninitialized variable in your replace expression (<TMPL_VAR NAME=\"$1\"$2>), you'll get the error you mention in your question.

To fix the issue, change your regular expression if possible, or you could create a small scope that temporarily disables the warning:

my $filter = sub {
    my $text_ref = shift;
    {
        no warnings qw/uninitialized/;
        $$text_ref =~ s/\[\%([^ ]+?)( .*)?\%\]/<TMPL_VAR NAME=\"$1\"$2>/g;
    }
}

Upvotes: 2

amon
amon

Reputation: 57656

You have the regex /\[\%([^ ]+?)( .*)?\%\]/. Or written more readable:

/
  \[\%
  ( [^ ]+? )  # $1
  ( [ ].* )?    # $2
  \%\]
/x

You might notice that the $2-group is completely optional. If the pattern for $2 doesn't match, it will be set to undef. It does not match if there isn't at least one space between the variable name and the closing %]: [%foo-bar%].

Possible solutions include:

  • changing the pattern for $2 so that it also accepts zero-length strings: ( .* )

  • using a default value for $2 before interpolating:

    s{\[\%([^ ]+?)( .*)?\%\]}{qq[<TMPL_VAR NAME="$1"] . ($2 // q[]) . q[>]}eg
    

    (will only work from perl 5.10 onwards)

  • switch off this warning in the scope of the filter: no warnings'uninitialized';.

Note that your substitution mechanism is susceptible to XML injection, and will have problems when a variable [% … %] block is stretched over multiple lines, or when two variables are on the same line. Assuming escape() escapes some data for safe use in XML, then the following should work:

s{
  \[%
  (\S+?)  # $1 is a sequence of non-space characters
  (?: \s+ ["]([^"]+)["] )?  # $2 is anything inside double quotes
  %\]
}{
  (defined $2)
  ? (sprintf q[<TMPL_VAR NAME="%s" "%s">], escape($1), escape($2))
  : (sprintf q[<TMPL_VAR NAME="%s">], escape($1))
}gsex

Upvotes: 8

Related Questions