Expanding Variables in User Input (Perl Cookbook, 2nd Edition)

## 1.12. Expanding Variables in User Input

### 1.12.1. Problem

You've read 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.

### 1.12.2. Solution

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;

### 1.12.3. Discussion

The first technique is basically to find what looks like a variable name, then use symbolic dereferencing to interpolate its contents. If `$1` contains the string `somevar`, `${$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:

>     our ($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 where you don't know the exact replacement value, but you do know how to calculate it. For example, 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 runtime. A small advantage of this scheme is that it doesn't require a `no` `strict` '`refs`' pragma for the block. A tremendous advantage is that unlike symbolic dereferencing, this mechanism finds 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 righthand side as code. The `/e` modifier gives 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;

Once upon a time, long ago and far away, `$$1` used to mean `${$}1` when it occurred within a string; that is, the `$$` variable followed by a `1`. This was grandfathered to work that way so you could more readily expand the `$$` variable as your process ID to compose temporary filenames. It now always means `${$1}`, i.e., dereference the contents of the `$1` variable. We have written it the more explicit way for clarity, not correctness.

### 1.12.4. See Also

The `s///` operator in perlre(1) and perlop(1) and Chapter 5 of Programming Perl; the `eval` function in perlfunc(1) and Chapter 29 of Programming Perl; the similar use of substitutions in Recipe 20.9

Copyright © 2003 O'Reilly & Associates. All rights reserved.