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

Hey there, Monks,

what's the best way to tap into Perl's double-quote-interpolation mechanism? Starting from strings like

my $var = "foo"; my $str = 'abc $var def';
(notice the single quotes in the second case), I'd like to get 'abc foo def' in $str.

Now, you could do something like

my $newstr = eval "\"$str\"";
but this will fail if $str contained a double-quote. You could escape literal double quotes before eval'ing and unescape them in the result -- but isn't there a better way to say "escape all variables in this string, just like double quotes would do"?

Replies are listed 'Best First'.
Re: Interpolating variables in a string
by chromatic (Archbishop) on Oct 13, 2004 at 23:01 UTC

    What are you trying to do?

    Sometimes I use sprintf:

    my $template = <<END_HERE; Hi, %s. I really like your %s shoes. Best, -- % END_HERE my $text = sprintf( $template, $name, $color, $sig );

    Other times, closures work nicely to bind to various values:

    my ($name, $color, $sig); my $template = sub { return <<END_HERE; Hi, $name. I really like your $color shoes. Best, -- $sig END_HERE }; $name = 'bob'; $color = 'blue'; $sig = 'c'; my $text = $template->();
Re: Interpolating variables in a string
by perrin (Chancellor) on Oct 13, 2004 at 22:29 UTC
      Actually, I was looking for a complete solution to tap into Perl's double quote interpolation mechanism. The solution proposed in the FAQ won't work in these cases:
      'abc @var def' 'abc ${var} def' 'abc $$var def'
        In that case, an eval like you used above is the only way. You can use quotemeta to escape the quotes.
Re: Interpolating variables in a string
by dpuu (Chaplain) on Oct 13, 2004 at 22:26 UTC
    You could try doing a here-script type of thing:
    my $token = "__UNIQUE_TOKEN__"; $token .= "_" while $str =~ /$token/; chomp (my $new_str = eval qq(<<"$token"\n$str\n$token));
    (I haven't tested that, but it feels like it might work). What I usually do for this type of thing is to not rely on lexical variables in my program, and instead set up a separate hash of legal variables:
    my %vars = ( var => "foo" ); $str = 'abc $var def'; (my $new_str = $str) =~ /\$(\w+)/$vars{$1}/g;
    --Dave
    Opinions my own; statements of fact may be in error.
Re: Interpolating variables in a string
by perlcapt (Pilgrim) on Oct 14, 2004 at 02:27 UTC
    Maybe I'm missing the point of this question, but the double quotes allow you to include variables. E.G.:
    $var = 'foo'; $str = "abc $var def"; print $str; abc foo def
    if you want to actually include single quotes in the $str, then escape them:
    $str = "\'abc $var def\'"; print $str; 'abc foo def'
Re: Interpolating variables in a string
by borisz (Canon) on Oct 13, 2004 at 22:26 UTC
    What about
    my $newstr = eval "qq{$str}";
    this works, even if $str contain a ".
    Boris
      Though not if it contains an unpaired '}'.
      --Dave
        then do it like the first poster suggest:
        ( my $newstr = $str ) =~ s/(\$\w+)/$1/eeg;
        Boris
Re: Interpolating variables in a string
by Cody Pendant (Prior) on Oct 14, 2004 at 02:43 UTC
    I just plain don't understand the question. If it's not "how do I interpolate vars in a string?" what is it? What is meant by "tap in to"? You can "tap into" the double-quote-interpolation mechanism by, well ... putting things in double-quotes.


    ($_='kkvvttuubbooppuuiiffssqqffssmmiibbddllffss')
    =~y~b-v~a-z~s; print
      The problem is that you can't just "put things in double quotes" at runtime.

      Let's assume that there's a string $string which I've just read from a file. The string contains 'abc $var def'. What I want is: Treat this string as if there were double quotes around it and interpolate any variables that are in it. Just as if it was "abc $var def" (double quotes) in a Perl program.

      The previous postings have shown that this is not a straight-forward task.

      So far, the only way I found to make this work (still with limitations) is to use something like this:

      my $x = "foo"; my $y = 'abc $x def\\/'; escape_slashes($y); $y = eval "qq/$y/"; unescape_slashes($y); print "y=$y\n"; sub escape_slashes { $_[0] =~ s#(\\|/)#\\\\$1#g; } sub unescape_slashes { $_[0] =~ s#(\\\\|\\/)#substr($1, 1, 1)#eg; }
      which just puts double quotes around the string, eval()s it and makes sure none of the characters in the string messes with the surrounding double quotes (or their qq// delimiter equivalents).

      The ideal solution would be to step down into the perl machine room and replicate exactly what happens during runtime if your program contains a string in double quotes:

      my $result = "abc $var def";
      does exactly the right thing, it interpolates correctly. So, who can show me that entrance to the machine room?

      Please don't just brush off this question by saying "Why on earth would you do that?". It's not about best programming practices. It's about language completeness.

      It's possible to do eval "perl code" in order to evaluate Perl code. Is it really necessary to resort to the kludge of saying eval "\"interpolate_this\"" (and deal with the resulting escape problems) to have a string interpreted as if it was inside double quotes?

Re: Interpolating variables in a string
by TedPride (Priest) on Oct 14, 2004 at 10:50 UTC
    my $aha = 'upon'; my $oho = 'a'; my $text = 'once $aha $oho time'; $text =~ s/\$(\w+)/${$1}/g; print $text;
    If you have variable names containing something other than just \w, you'll have to expand the regex a bit, but there's the mechanism you need. ${'varnam'} is the same as $varname.