Reputation: 83
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
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
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
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