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

Hi,

I'm using Perl to scan a text file with contents somewhat resembling this:

User:
Messages:message1,message2,message3
Color1:
Color2:

And I've already got all the messages in @messages.
Problem is, @messages can have strings like "Today is $time[1] and you have seen this $counter times!" or something.
In my script, I've declared all the vars (in this example, @time and $counter are declared). But when I print that $message via a loop, it doesnt interpolate $counter or $time[1], it just prints them in plaintext =(
I'm printing them like this:
foreach $message(@messages) { print "$message<br />"; }
But it still doesnt, even with " and not '. Any idea what I might do? I saw some replacing (I think it was s/\$(\w+)/$$1/ or something) but "use strict" doesnt allow it, and it doesnt work at all even without strict exiting the program D=

Replies are listed 'Best First'.
Re: Parsing a string from a file
by davidrw (Prior) on Jun 11, 2005 at 15:23 UTC
    Assuming the variables are declared, you can use eval ... BUT be very careful and be sure that you trust the data (i.e. that system() commands, etc can't be injected).

    Basically, we want to accomplish this:
    my @time = (1, 2, 3); my $counter = 5; my $s = "Today is $time[1] and you have seen this $counter times!"; print "$s";
    So what we can do is this:
    my @time = (1, 2, 3); my $counter = 5; my $s = 'Today is $time[1] and you have seen this $counter times!'; warn $s; warn eval "\"$s\""; __END__ Today is $time[1] and you have seen this $counter times! at blah.pl li +ne 4. Today is 2 and you have seen this 5 times! at blah.pl line 5.
      Many thanks!
      *will remember eval for future use* :D
      And about the integrity of the data, I'm inputting it myself in these text files :D
      Again, thanks!
        Ah, so these are self-created data files? In that case (since you can format the data any way you want) you may want to consider using an existing template solution like Template Toolkit. This way you don't need to worry about eval or anything like that, plus you gets tons of other functionality.
        my @time = (1, 2, 3); my $counter = 5; my $data = { counter => $counter, time => \@time, }; my $s = 'Today is [% time.1 %] and you have seen this [% counter %] ti +me[% "s" IF counter > 1 %]!'; warn $s; use Template; my $template = Template->new(); my $out = ''; $template->process(\$s, $data, \$out) or die $template->error; warn $out; __END__ ~~~Output~~~: Today is [% time.1 %] and you have seen this [% counter %] time[% "s" +IF counter > 1 %]! at /tmp/t line 8. Today is 2 and you have seen this 5 times! at /tmp/t line 13.
Re: Parsing a string from a file
by davido (Cardinal) on Jun 11, 2005 at 16:08 UTC

    Strict doesn't allow it because it is a very bad idea. ...a design flaw in your code. What you are trying to do is use symbolic references. What you should be doing is using a hashtable (a hash). Why? What happens when one of the messages contains a variable name that is already used in your script for something else? You'll have a bug that is very difficult to trace.

    You want something like this:

    foreach my $message ( @messages ) { print "$hash{$message}<br />\n"; }

    And that means you'll need to redesign so as to use a hash instead of symbolic references as your message container.

    Just because symbolic refs are possible in Perl doesn't mean you should be using them.


    Dave

Re: Parsing a string from a file
by chas (Priest) on Jun 11, 2005 at 17:30 UTC
    If you are using double quotes as you indicate, there isn't an interpolation problem; am I missing something?
    my @time = (1, 2, 3); my $counter = 5; my $s = "Today is $time[1] and you have seen this $counter times!"; @messages=($s); foreach $m(@messages){print "$m\n";}

    Output:
    Today is 2 and you have seen this 5 times!
    chas
    (Update: Also, if I read the lines from a file using the diamond operator and push them onto @messages, it seems to work fine.)
Re: Parsing a string from a file
by mda2 (Hermit) on Jun 13, 2005 at 01:39 UTC
    Today you have many template tools (Template::Tolkit, HTML::Mason, etc). But if you need a single template for pages you can use reserved words to do it.

    For example, use TIME and COUNT to replace messages...

    foreach $message (@messages) { $message =~ s/TIME/$time/g; $message =~ s/COUNT/$count/g; print "$message<br />"; }

    But if you need many reserved words it can have more or less cpu costs...
    But it more secure with use eval...

    --
    Marco Antonio
    Rio-PM