Robert Spier <[EMAIL PROTECTED]> writes:

> Thanks for the patch, but I don't think it makes sense:
> 
> > After numerous heated debates on comp.lang.perl.* here is my new
> > improved answer for perlfaq4: expanding variables in strings. 
> 
> I'm not sure it's "improved".
> 
> First, please adhere to the line wrapping used in the rest of the
> document. 

Sorry.

> > -See also ``How can I expand variables in text strings?'' in this
> > +See also ``How can I expand/interpolate variables in text strings?'' in this
> >  section of the FAQ.
> 
> I'm not sure the renaming makes sense.

The word "expand" is not the natural term to decsribe what is going
on.  The word "interpolate" is.  People have asked this FAQ in
newsgroups because, understanably, they looked in the FAQ for
"interpolate" or "interpolation" then gave up.
 
> > -=head2 How can I expand variables in text strings?
> > -
> > -Let's assume that you have a string like:
> > +=head2 How can I expand/interpolate variables in text strings?
> 
> You've snipped the descriptive part.

Yes, it added nothing.  Keep it if you like.

> > -    $text = 'this has a $foo in it and a $bar';
> > +    $text = 'this has a $foo in it...\n  ...and a $bar';
> > +    # Assume $text does not contain "\nEND\n" 
> > +    chop ( $text = chop "<<END\n$text\nEND\n" );
> > +    die if $@;
> 
> What are you trying to do here?

Opps typo, second chop should, of course, be eval.  This is the true
answer to the question most people would be asking.  They are not
looking for a way to reinvent the interpolation mechanism but a way to
use the one they know is already there.  I think that the answer in
the FAQ should answer the question in the FAQ (if a trivial answer
exists) even if it then goes on to describe alternative approaches.

Many other people (including MJD) have expressed frustration that the
FAQ does not actually give the answer in this case.

> > -If those were both global variables, then this would
> > -suffice:
> > +This is dangerous if the text comes form an untrusted source,
> > +consider:
> >  
> > -    $text =~ s/\$(\w+)/${$1}/g;  # no /e needed
> > +    $text = '@{[ system "rm -rf /" ]}';
> 
> Why did you remove the simple and safe example of inserting global
> variables?

See recent discussions in comp.lang.perl.*.  Brian d Foy indicated
that he felt this FAQ was getting too involved and that if the true
answer was to be included then other stuff must be lost. Global
variables are very little used in Perl and so it's very unlikely that
the variables one wants to interpolate would already be globals.  The
symbolic reference solution is only marginally simpler and no safer
than the ee one. Converting lexical variables to global just so one
could use symbolic references rather than eval would not be warranted.
As such the symbolic reference solution would be applicable only
extreely rarely and does not justify a mention if we are trying to
keep this brief.

> Also, the system example is overly complicated to use in the FAQ
> without explaining it.

OK, then re-instate the cross reference to the relevant FAQ at this
point.

> > -But since they are probably lexicals, or at least, they could
> > -be, you'd have to do this:
> > +If you only need to process simple scalars then you can do limit the
> > +parts of the string that are passed to eval() like this:
> >  
> >      $text =~ s/(\$\w+)/$1/eeg;
> >      die if $@;                     # needed /ee, not /e
> >  
> > -It's probably better in the general case to treat those
> > -variables as entries in some special hash.  For example:
> > +This still gives unrestricted access to your scalar variables.  It is
> > +often better to use a hash:
> 
> I don't think this sentence is any clearer.

It gives at least some indication as to _why_ it is better.  It
removes the meaningless (and hense potentially confusing) use of the
word "special".  It removes the inappropriate term "general case".
This is, in fact, a solution to a much less general (albeit frequently
encountered) case.

> >  
> >      %user_defs = ( 
> >     foo  => 23,
> > @@ -924,8 +928,8 @@
> >      );
> >      $text =~ s/\$(\w+)/$user_defs{$1}/g;
> >  
> > -See also ``How do I expand function calls in a string?'' in this section
> > -of the FAQ.
> > +For other variations on the theme of text templates see the sprintf()
> > +function and numerous modules on CPAN.
> 
> Why did you take out the reference?

Because the questions are, in fact, largely unlrelated and the answer
that one is no help in answering this one.  The only possible reason
to mention the "functions" FAQ is to illustrate why the eval solution
is dangerous.  In the version of the FAQ that didn't mention the eval
solution this was kinda pointless.  I've reinstated the
cross-reference further up.

I've also noticed that the mistake in the answer to the "functions"
FAQ (that previously I patched, and that I belived had been committed)
is still there.  It is just plain wrong to say that ${\($n + 5)}
evaluates the experession in a scalar context. The FAQ says, "Version
5.004 of Perl had a bug that gave list context to the expression in
C<${...}>, but this is fixed in version 5.005.".  This is true but
totally irrelevant as \(...) does not propagate the scalar context.

perl -e 'sub foo { wantarray }; print "${\(foo)}"';

Anyhow, take 3...
--- perlfaq4.pod        Thu Mar  6 18:03:55 2003
+++ perlfaq4-bam.pod    Mon Mar 10 11:12:48 2003
@@ -539,6 +539,9 @@
 
 This won't expand C<"\n"> or C<"\t"> or any other special escapes.
 
+See also ``How can I expand/interpolate variables in text strings?''
+in this section of the FAQ.
+
 =head2 How do I remove consecutive pairs of characters?
 
 To turn C<"abbcccd"> into C<"abccd">:
@@ -557,16 +560,8 @@
 
     print "My sub returned @{[mysub(1,2,3)]} that time.\n";
 
-If you prefer scalar context, similar chicanery is also useful for
-arbitrary expressions:
-
-    print "That yields ${\($n + 5)} widgets\n";
-
-Version 5.004 of Perl had a bug that gave list context to the
-expression in C<${...}>, but this is fixed in version 5.005.
-
-See also ``How can I expand variables in text strings?'' in this
-section of the FAQ.
+See also ``How can I expand/interpolate variables in text strings?''
+in this section of the FAQ.
 
 =head2 How do I find matching/nesting anything?
 
@@ -898,25 +893,27 @@
 If Text::Soundex does not do what you are looking for, you might want
 to consider the String::Approx module available at CPAN.
 
-=head2 How can I expand variables in text strings?
-
-Let's assume that you have a string like:
+=head2 How can I expand/interpolate variables in text strings?
 
-    $text = 'this has a $foo in it and a $bar';
+    $text = 'this has a $foo in it...\n  ...and a $bar';
+    # Assume $text does not contain "\nEND\n" 
+    chop ( $text = eval "<<END\n$text\nEND\n" );
+    die if $@;
 
-If those were both global variables, then this would
-suffice:
+This is dangerous if the text comes form an untrusted source, consider
+the effect of the following (for explaination see ``How do I expand
+function calls in a string?'' in this section of the FAQ).
 
-    $text =~ s/\$(\w+)/${$1}/g;  # no /e needed
+    $text = '@{[ system "rm -rf /" ]}';
 
-But since they are probably lexicals, or at least, they could
-be, you'd have to do this:
+If you only need to process simple scalars then you can do limit the
+parts of the string that are passed to eval() like this:
 
-    $text =~ s/(\$\w+)/$1/eeg;
-    die if $@;                 # needed /ee, not /e
+    $text =~ s/(\$\w+)/$1/eeg; # needed /ee, not /e
+    die if $@;
 
-It's probably better in the general case to treat those
-variables as entries in some special hash.  For example:
+This still gives unrestricted access to your scalar variables.  It is
+often better to use a hash:
 
     %user_defs = ( 
        foo  => 23,
@@ -924,8 +921,8 @@
     );
     $text =~ s/\$(\w+)/$user_defs{$1}/g;
 
-See also ``How do I expand function calls in a string?'' in this section
-of the FAQ.
+For other variations on the theme of text templates see the sprintf()
+function and numerous modules on CPAN.
 
 =head2 What's wrong with always quoting "$vars"?
 
 
-- 
     \\   ( )
  .  _\\__[oo
 .__/  \\ /\@
 .  l___\\
  # ll  l\\
 ###LL  LL\\

Reply via email to