You've read in a string with an embedded variable reference, such as:
You owe $debt to me.
Now you want to replace
$debt
in the string with its value.
Use a substitution with symbolic references if the variables are all globals:
$text =~ s/\$(\w+)/${$1}/g;
But use a double
/ee
if they might be lexical (
my
) variables:
$text =~ s/(\$\w+)/$1/gee;
The first technique is basically "find what looks like a variable name, and then use symbolic dereferencing to interpolate its contents." If
$1
contains the string
somevar
, then
${$1}
will be whatever
$somevar
contains. This won't work if the
use
strict
'refs'
pragma is in effect because that bans symbolic dereferencing.
Here's an example:
use vars qw($rows $cols); no strict 'refs'; # for ${$1}/g below my $text; ($rows, $cols) = (24, 80); $text = q(I am $rows high and $cols long); # like single quotes! $text =~ s/\$(\w+)/${$1}/g; print $text;
I am 24 high and 80 long
You may have seen the
/e
substitution modifier used to evaluate the replacement as code rather than as a string. It's designed for situations such as doubling every whole number in a string:
$text = "I am 17 years old"; $text =~ s/(\d+)/2 * $1/eg;
When Perl is compiling your program and sees a
/e
on a substitute, it compiles the code in the replacement block along with the rest of your program, long before the substitution actually happens. When a substitution is made,
$1
is replaced with the string that matched. The code to evaluate would then be something like:
2 * 17
If we tried saying:
$text = 'I am $AGE years old'; # note single quotes $text =~ s/(\$\w+)/$1/eg; # WRONG
assuming
$text
held a mention of the variable
$AGE
, Perl would dutifully replace
$1
with
$AGE
and then evaluate code that looked like:
'$AGE'
which just yields us our original string back again. We need to evaluate the result
again
to get the value of the variable. To do that, just add another
/e
:
$text =~ s/(\$\w+)/$1/eeg; # finds my() variables
Yes, you can have as many
/e
modifiers as you'd like. Only the first one is compiled and syntax-checked with the rest of your program. This makes it work like the
eval
{BLOCK}
construct, except that it doesn't trap exceptions. Think of it more as a
do
{BLOCK}
instead.
Subsequent
/e
modifiers are quite different. They're more like the
eval
"
STRING
" construct. They don't get compiled until run-time. A small advantage of this scheme is that it doesn't make you put a
no
strict
'refs'
pragma in the block. A tremendous advantage is that unlike the symbolic dereferencing, this mechanism can actually find lexical variables created with
my
, something symbolic references can never do.
The following example uses the
/x
modifier to enable whitespace and comments in the pattern part of the substitute and
/e
to evaluate the right-hand side as code. The
/e
modifier gives you more control over what happens in case of error or other extenuating circumstances, as we have here:
# expand variables in $text, but put an error message in # if the variable isn't defined $text =~ s{ \$ # find a literal dollar sign (\w+) # find a "word" and store it in $1 }{ no strict 'refs'; # for $$1 below if (defined $$1) { $$1; # expand global variables only } else { "[NO VARIABLE: \$$1]"; # error msg } }egx;
Note that the syntax of
$$1
has changed for Perl 5.004: it used to mean
${$}1
but now means
${$1}
. For backwards compatibility, in strings it still takes the old meaning (but generates a warning with
-w
). People will write
${$1}
within a string to keep from dereferencing the PID variable. If
$$
were 23448, then
$$1
in a string would turn into
234481
, not the contents of the variable whose name was stored in
$1
.
The
s///
operator in
perlre
(1) and
perlop
(1) and the
"Pattern Matching"
and
"Regular Expressions"
sections of
Chapter 2
of
Programming Perl
; the
eval
function in
perlfunc
(1) and
Chapter 3
of
Programming Perl
; the similar use of substitutions in
Recipe 20.9
.