Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Double Interpolation of a String

by chromatic (Archbishop)
on May 18, 2000 at 04:45 UTC ( [id://12275]=CUFP: print w/replies, xml ) Need Help??

Suppose you have a string with variable names in it. You want them to be expanded when you print it, but you're not sure how. Never fear, you can abuse eval()!
my $color = "red"; my $fruit = "apple"; my $name = "chromatic"; my $string = 'Hi, my name is $name. Please hand me a $color $fruit.'; print ">>$string<<\n"; # demonstrate what we have my $s2; eval "\$s2 = qq/$string/"; # the real magic print "->$s2<-\n"; # demonstrate the result

Replies are listed 'Best First'.
RE: Double Interpolation of a String
by davorg (Chancellor) on Jun 22, 2000 at 14:30 UTC

    For doing stuff with these kinds of substitutions, I always use code like this:

    use strict; my %trans = (color => 'red', fruit => 'apple', name => 'chromatic'); my $string = 'Hi, my name is $name. Please hand me a $color $fruit.'; $string =~ s/\$(\w+)/$trans{$1}/eg; print $string;

    --
    <http://www.dave.org.uk>

    European Perl Conference - Sept 22/24 2000
    <http://www.yapc.org/Europe/>
      With inspiration from davorg's above example, taking it a step further (and a step further (and a step further (...))):
      #!/usr/bin/perl -w use strict; my %trans = ( '$name' => 'Frank', '$color' => 'Cherry Red', '$time' => sprintf ("%d:%02d:%02d", (localtime(time))[2,1,0]), '$date' => sprintf ("%04d-%02d-%02d", (localtime(time))[5] + 1900, (localtime(time))[4] + 1, (localtime(time))[3]), '$dstr' => '$time on $date', ); my ($trans_rx) = join ('|', sort { length($b) - length($a) } sort map { quotemeta ($_) } keys %trans); my ($string) = 'I\'m $name and I prefer $color objects, at least +on $dstr'; while ($string =~ s!($trans_rx)!$trans{$1}!o) { } print "$string\n";
      For output like:
      I'm Frank and I prefer Cherry Red objects, at least on 15:33:43 o +n 2001-02-06
      This version doesn't replace stray references to things like $1.95 with nothing, but it might get caught in a loop if you specify two entries which convert to eachother recursively such that "$a -> $b" and "$b -> $a".
        It might be useful to protect against infinite recursion as well:
        my $max_recurs = 10; $max_recurs-- while $string =~ ... && $max_recurs; warn "Too many recursive substitutions on '$string'" if !$max_recurs && $^W;
Re: Double Interpolation of a String
by nontrivial (Novice) on Aug 21, 2001 at 06:20 UTC
    Brother chromatic, I am not having much success reproducing this. If I create this simple script it works. However, if I try it in an application I am working on it doesn't. After a few hours of frustration I have decided to punt. Help please? Here is a chunk of my code. I am pulling the string out of the database instead of arbitrarily setting it:
    my $WhereVal = $Return->[0]->{WhereVal}; my $Temp2 = 2; warn $WhereVal; eval "\$Temp = qq/$WhereVal/"; warn $Temp;
    The result is that the eval fails. The log shows:
    c.AppModule=m.AppModule and m.Application=$Temp2 at (eval 43) line 19. Use of uninitialized value in concatenation (.) at (eval 43) line 20. Use of uninitialized value in warn at (eval 43) line 21.
    The complete subroutine, less gratuitous debugging code:
    sub VWP_RunQuery { my ($QueryRef, @Params) = @_; if ($QueryRef) { VWP_Log(5, "Running query $QueryRef..."); my $stt = "select q.FromVal, q.OrderVal, q.SelectVal, q.WhereVal " + . "from VWPQuery q, VWPQueryRef qr where q.Query=qr.Query and " . "qr.DBType = ? and qr.Query = ?"; my $Return = VWP_SQL($stt, ($Session::DBType, $QueryRef)); if (@$Return) { my $OrderVal = $Return->[0]->{OrderVal}; $stt = "select " . $Return->[0]->{SelectVal} . " from " . $Return->[0]->{FromVal}; if ($Return->[0]->{WhereVal}) { my $WhereVal; eval "\$WhereVal = qq/$Return->[0]->{WhereVal}/"; $stt = $stt . " where " . $WhereVal; } if ($OrderVal) { if (($OrderVal =~ /order by/) || ($OrderVal =~ /ORDER BY/)) { $stt = $stt . " " . $OrderVal; } else { $stt = $stt . " order by " . $OrderVal; } } return VWP_SQL($stt, @Params); } } VWP_StrMessage(1, 13, $QueryRef); }
      It's possible that $stt is empty in some of the concatenations. A couple of minor style issues might clear it up.

      Otherwise, it depends a lot on what's coming back from the database. Without seeing that, it's hard to know what the trouble is. As a side note, I personally wouldn't use this for such a thing. It's very hard to control what variables are in scope and accessible when you pull information out of a database like this.

      There's probably a better way. If you describe the situation in SoPW, you'll probably get two or three alternate ideas that aren't as fragile.

      sub VWP_RunQuery { my ($QueryRef, @Params) = @_; if ($QueryRef) { VWP_Log(5, "Running query $QueryRef..."); my $stt = "select q.FromVal, q.OrderVal, q.SelectVal, q.WhereV +al " . "from VWPQuery q, VWPQueryRef qr where q.Query=qr.Query and " +. "qr.DBType = ? and qr.Query = ?"; my $Return = VWP_SQL($stt, ($Session::DBType, $QueryRef)); if (@$Return) { my $OrderVal = $Return->[0]->{OrderVal}; $stt = "select " . $Return->[0]->{SelectVal} . " from " . $Return->[0]->{FromVal}; if ($Return->[0]->{WhereVal}) { my $WhereVal = eval "qq/$Return->[0]->{WhereVal}/"; $stt .= " where " . $WhereVal; } if ($OrderVal) { $stt .= " order by" unless $OrderVal =~ /^order by/i; $stt .= " $OrderVal"; } return VWP_SQL($stt, @Params); } } VWP_StrMessage(1, 13, $QueryRef); }
Re: Double Interpolation of a String
by 5mi11er (Deacon) on Feb 01, 2007 at 22:26 UTC
    Having just needed something along these lines, and after reading through the Dreaming of Post Interpolation thread, I think I've settled on using something like this:
    @lines = <<TEXT_INFO; Dear \$person, I know that this text is \$adjective. But I wish it could be... This is a test of imbedded variables I want to set \\\$variable later, and then have it interepreted when + printed variable was set to \$variable TEXT_INFO $variable = 5; my $person = 'Mom'; my $adjective = 'not interpolated'; foreach $line (@lines) { print eval "qq{$line}"; }
    -Scott

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: CUFP [id://12275]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2024-03-28 20:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found