in reply to Uninitialized scalar inside a scalar?

You know why single quotes don't work; variables don't get interpolated in single-quoted strings.

Double quotes don't work because the value of the string which interpolates $1 gets evaluated at the point of assignment, which occurs before the regular expression match.

You need to delay the evaluation of $1 until the point at which it contains a value you want to interpolate into a string. One way to do that is to define $outputString within the if block. Another approach is to use an anonymous function.

use 5.010; my $make_output_string = sub { "this is a $_[0]" }; ... if ($sample_data =~ m/$search_string/) { say $make_output_string->($1); }

(You don't have to use 5.10 to make this work, but I really like say.)

Replies are listed 'Best First'.
Re^2: Uninitialized scalar inside a scalar?
by n00bsauce (Initiate) on Jan 07, 2009 at 22:06 UTC
    I've simplified the previous example. The problem is I don't know what will be pulled from the string or how it will be put together in the output. So the sub call would fail if
    $searchString = "(T)(est).(.{2}).*"; $outputString = 'This $3 a $1$2'; $sampleData = "Test is good";
    because I would only be sending $1.

    I need to be able to have a regex in that splits up the string, and then another string that defines how to piece it back together. The way it is split up and recombined needs to be able to change. Sorry if I didn't explain it very well.

      If you completely trust your $outputString not to have anything malicious in it, you could use string eval.

      $searchString = '(T)(est).(\d{2}).*'; $outputString = 'This $3 a $1$2'; $sampleData = "Test 22"; $sampleData =~ /$searchString/ && eval qq{print "$outputString"}; print "\n"; __END__ This 22 a Test

      I think, however, this should be considered a last resort.

      If I'm not missing something you can generalize the principle to any number of parameters. Parameters you don't need are undef or garbage, but that should not matter

      $searchString = "(T)(est).(.{2}).*"; $outputString = 'This $3 a $1$2'; $sampleData = "Test is good"; if ($sample_data =~ m/$search_string/) { say $make_output_string->($1,$2,$3,$4,$5,$6,$7,$8); }

      You could to this with a little eval magic (see the caveats, later). What I have in mind would be something like the following:

      if( $sampleData =~ /$searchString/ ) { print eval qq{"$outputString"}; }

      The outer qq{} quote is used to generate an evaluateable string by adding double quotes around the original. When evaluated, this new string interpolates your variables into place.

      There are a few problems with this approach:

      • You may need to escape characters in the string (: at a minimum)
      • This is effectively compiled at run-time, which means unexpected errors can result.
      • You need to carefully scrub the output strings to prevent injection attacks.

      You are basically trusting the incoming string to be safe to evaluate and run as code. This is not always a valid or safe assumption.

      G. Wade