0

My code is below:

use strict;

my $store = 'Media Markt';
my $sentence = "I visited [store]";

# Replace characters "[" and "]"
$sentence =~ s/\[/\$/g;
$sentence =~ s/\]//g;

print $sentence;

I see following at screen:

I visited $store

Is it possible to see following? I want to see value of $store:

I visited Media Markt

kadir_beyazli
  • 197
  • 2
  • 12

2 Answers2

3

You seem to be thinking of using a string, 'store', in order to build a variable name, $store. This gets to the subject of symbolic references, and you do not want to go there.

One way to do what you want is to build a hash that relates such strings to corresponding variables. Then capture the bracketed strings in the sentence and replace them by their hash values

use warnings;
use strict;

my $store = 'Media Markt';
my $time  = 'morning';

my %repl = ( store => $store, time => $time );

my $sentence = "I visited [store] in the [time]";

$sentence =~ s/\[ ([^]]+) \]/$repl{$1}/gex;

print "$sentence\n";

This prints the line I visited Media Markt in the morning

The regex captures anything between [ ], by using the negated character class [^]] (any char other than ]), matched one-or-more times (+). Then it replaces that with its value in the hash, using /e to evaluate the replacement side as an expression. Since brackets are matched as well they end up being removed. The /x allows spaces inside, for readibilty.

For each string found in brackets there must be a key-value pair in the hash or you'll get a warning. To account for this, we can provide an alternative

$sentence =~ s{\[ ([^]+) \]}{$repl{$1}//"[$1]"}gex;

The defined-or operator (//) puts back "[$1]" if $repl{$1} returns undef (no key $1 in the hash, or it has undef value). Thus strings which have no hash pairs are unchanged. I changed the delimiters to s{}{} so that // can be used inside.

This does not allow nesting (like [store [name]]), does not handle multiline strings, and has other limitations. But it should work for reasonable cases.

zdim
  • 64,580
  • 5
  • 52
  • 81
  • OP may go with just an array of objects If she thinks about dynamically added code. – Pavel Feb 18 '17 at 19:38
  • @paveljurca I completely agree that there are other ways to pursue what seems to be the idea, and that OO approach would be good. – zdim Feb 19 '17 at 06:38
2

As I told you on the Perl Programmers Facebook group, this is very similar to one of the answers in the Perl FAQ.

How can I expand variables in text strings?

If you can avoid it, don't, or if you can use a templating system, such as Text::Template or Template Toolkit, do that instead. You might even be able to get the job done with sprintf or printf:

my $string = sprintf 'Say hello to %s and %s', $foo, $bar;

However, for the one-off simple case where I don't want to pull out a full templating system, I'll use a string that has two Perl scalar variables in it. In this example, I want to expand $foo and $bar to their variable's values:

my $foo = 'Fred';
my $bar = 'Barney';
$string = 'Say hello to $foo and $bar';

One way I can do this involves the substitution operator and a double /e flag. The first /e evaluates $1 on the replacement side and turns it into $foo. The second /e starts with $foo and replaces it with its value. $foo, then, turns into 'Fred', and that's finally what's left in the string:

$string =~ s/(\$\w+)/$1/eeg; # 'Say hello to Fred and Barney'

The /e will also silently ignore violations of strict, replacing undefined variable names with the empty string. Since I'm using the /e flag (twice even!), I have all of the same security problems I have with eval in its string form. If there's something odd in $foo, perhaps something like @{[ system "rm -rf /" ]}, then I could get myself in trouble.

To get around the security problem, I could also pull the values from a hash instead of evaluating variable names. Using a single /e, I can check the hash to ensure the value exists, and if it doesn't, I can replace the missing value with a marker, in this case ??? to signal that I missed something:

my $string = 'This has $foo and $bar';
my %Replacements = (
    foo  => 'Fred',
    );
# $string =~ s/\$(\w+)/$Replacements{$1}/g;
$string =~ s/\$(\w+)/
            exists $Replacements{$1} ? $Replacements{$1} : '???'
            /eg;
print $string;

And the actual (but really not recommended - for the reasons explained in the FAQ above) answer to your question is:

$sentence =~ s/\[(\w+)]/'$' . $1/ee;
Community
  • 1
  • 1
Dave Cross
  • 68,119
  • 3
  • 51
  • 97