Replacing variable names with values via reference in regexp

C

Ceesaxp

Hi,

I am trying to make a small template-like expansion in my code, though
I could fetch variable values via a reference but looks like I am
stuck. A sample code like this:

$var = "variable";
$a = 'This is a string with a <%=var%>!'; # single-quoted for no
variable substitution
$a =~ s/<%=([a-z]+)%>/{ $v=$1; $$v; }/eg;
print $a;

works. However, when I put it into larger code like this:

#! /usr/bin/perl -w
use strict 'vars';

my $template1 = 'This is a string with a <%=var%>!';
my $template2 = 'This is a string with a <%=main::var%>!';
my $var = 'variable';
print tmplParse($template1)."\n";
print tmplParse($template2)."\n";

sub tmplParse {
my $tmpl = shift;
my $v;
$tmpl =~ s/<%=([a-z:0-9_]+)%>/{ $v=$1; warn "\$v is now '$v'\t \$\$v
is '$$v'\n"; $$v; }/eg;
return $tmpl;
}

All I keep on getting is

Use of uninitialized value in concatenation (.) or string at
template.pl line 13.

(which is where substitution should happen)

If my reading is correct, it is unable to find a reference to either
$var or $main::var. But even if I define a local $var and set its
value inside of tmplParse, I still get the same error.

Any ideas, pointers, suggestions?

Thanks,
Andrei
 
G

Gunnar Hjalmarsson

Ceesaxp said:
I am trying to make a small template-like expansion in my code,

Use a hash:

use strict;
use warnings;

my $template = 'This is a string with a <%=var%>!';
my %vars = ( var => 'variable' );

print tmplParse($template, \%vars)."\n";

sub tmplParse {
my ($tmpl, $vars) = @_;
$tmpl =~ s/<%=([a-z:0-9_]+)%>/$vars->{$1}/g;
$tmpl;
}
 
U

Uri Guttman

C> $var = "variable";
C> $a = 'This is a string with a <%=var%>!'; # single-quoted for no
C> variable substitution
C> $a =~ s/<%=([a-z]+)%>/{ $v=$1; $$v; }/eg;
C> print $a;

that is using eval string and that is very bad. you are reinventing too
many template engines. but check out Template::Simple which does what
you want and is easy to learn.

uri
 
C

Ceesaxp

Uri said:
that is using eval string and that is very bad. you are reinventing too
many template engines. but check out Template::Simple which does what
you want and is easy to learn.

Thanks, Uri. I'll definitely check it out. Since it is a single and
pure Perl, I amy be able to incorporate it into the project, without
having to install it via CPAN.

A.
 
C

Ceesaxp

A. Sinan Unur said:
Why re-invent the wheel? Look at CPAN for many excellent templating
modules such as Text::Template, Template Toolkit, HTML::Template etc.

Because I can't use them in this particular case -- I have to do with
just a standard Perl distribution.
You are trying to use symbolic references. The FAQ explains why that is
not a good idea.

I am aware of this, but thanks for pointing it one more time.
In some shells, that will look for a path starting with a space. Use

#!/usr/bin/perl

Yeah, and on some systems it ain't in /usr/bin. Might even be in
C:\Perl. This is not, however, the point.
Symbolic references can only be used with global variables. Better to
use a hash for template expansion:

my %template_vars = (
var => 'variable',
);

Thanks -- this was the pearl of the reply.

I did not want to use a hash -- I sort of want it to work regardless of
a hash definition. This is also why I did no want to just borrow from
Text::Replace (which also uses a hash). Essentially, I want to replace
a <%=var%> with it's value if it exists, or silently fail (or
complain).


Andrei
 
B

Brian McCauley

Uri said:
C> $var = "variable";
C> $a = 'This is a string with a <%=var%>!'; # single-quoted for no
C> variable substitution
C> $a =~ s/<%=([a-z]+)%>/{ $v=$1; $$v; }/eg;
C> print $a;

that is using eval string

No, it's using symrefs.
and that is very bad.

Well, at least not something to be done lightly.

There is a widely repeated misconception that the /e switch on s/// is
in some way related to eval(STRING). This is wrong. s///ee is related
to eval(STRING) but the single /e just causes the RHS to be treated
like a BLOCK. s///e does not involve runtime compilation any more than
grep {BLOCK} LIST involves runtime compilation.

Indeed I find it helps to think of s///e as the most primative
operation and think of s/// and s///ee in terms of being shorthands for
special cases of s///e.

s/FOO/BAR/e can be thought of as a weird sytax for
do_substitute(qr/FOO/,sub{BAR})

s/FOO/BAR/ is short for s/FOO/ "BAR" /e;
sFOO/BAR/ee is short for for s/FOO/ eval(BAR) /e;
 
U

Uri Guttman

C> $var = "variable";
C> $a = 'This is a string with a <%=var%>!'; # single-quoted for no
C> variable substitution

BM> No, it's using symrefs.

BM> Well, at least not something to be done lightly.

BM> There is a widely repeated misconception that the /e switch on s/// is
BM> in some way related to eval(STRING). This is wrong. s///ee is related
BM> to eval(STRING) but the single /e just causes the RHS to be treated
BM> like a BLOCK. s///e does not involve runtime compilation any more than
BM> grep {BLOCK} LIST involves runtime compilation.


i know about /e but i misread the code. i originally was going to say it
was symrefs and some little demon in my head changed it to string
eval. /ee does do string eval. in any case the replacement expression
was way bad.

uri
 
U

Uri Guttman

C> Thanks -- this was the pearl of the reply.

C> I did not want to use a hash -- I sort of want it to work regardless of
C> a hash definition. This is also why I did no want to just borrow from
C> Text::Replace (which also uses a hash). Essentially, I want to replace
C> a <%=var%> with it's value if it exists, or silently fail (or
C> complain).

if that was the pearl of the reply why do you still want to ignore it?
symrefs are bad enough but having to manage many GLOBAL scalar vars for
your template is very dangerous and just bad coding. munging values in
the symbol table is just using a specialized hash with the side effect
of munging symbols. you don't need nor want that. use a hash or a
module. others have told you this as have i. don't be stubborn and
ignore all this correct advice.

uri
 
B

Brian McCauley

BM> There is a widely repeated misconception that the /e switch on s/// is
BM> in some way related to eval(STRING). This is wrong.
i know about /e but i misread the code.

I suspected that _you_ knew. However since you are generally considered
fairly authoratative I figured it was worth correcting you in public.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,001
Messages
2,570,255
Members
46,856
Latest member
MyronKatz6

Latest Threads

Top