Storing a substitution (similar to qr())

A

Arvin Portlock

I know how to store a regular expression using qr() but
I can't figure out a way to store the substitution part
of a substitution. For example, this works:

my $example = 'I match this string';
my $match = 'this string';
my $repl = 'that string';
my $regexp = qr($match);
$example =~ s/$regexp/$repl/;

and I get 'I match that string';

But I want to do something like this:

my $example = 'I saw Bob and Alice';
my $match = 'I saw (.*) and (.*)';
my $repl = 'I saw $2 and $1';
my $regexp = qr($match);
$example =~ s/$regexp/$repl/;
print $example;

However this gives me 'I saw $2 and $1' and what I want
is 'I saw Alice and Bob'.

Is there any way to do what I want? I'd like to know the
exact mechanics rather than using some module or another.
Also, is there a way to store the entire substitution, a la
my $subst = qr(s/$regexp/$repl/)?
 
T

Tad McClellan

Arvin Portlock said:
I know how to store a regular expression using qr() but
I can't figure out a way to store the substitution part
of a substitution.


The "substitution part" is also known as "a string". :)

(but your problem would be solved it you could make it
"some Perl code" instead, see below.
)
But I want to do something like this:
my $match = 'I saw (.*) and (.*)';
my $repl = 'I saw $2 and $1';
my $regexp = qr($match);
$example =~ s/$regexp/$repl/;

Is there any way to do what I want?


perldoc -q string

How can I expand variables in text strings?

Then:

my $repl = '"I saw $2 and $1"';
^ ^ note the quotes
...
$example =~ s/$regexp/$repl/ee;
 
A

Arvin Portlock

my $repl = '"I saw $2 and $1"';
^ ^ note the quotes
...
$example =~ s/$regexp/$repl/ee;


I've never seen 'ee' at the end of a substitution before.
It's contained in an example in perlop but without any
explanation as far as I can find.

Although your example worked I haven't managed to get
it to work in my particular situation, where a list of
these substitutions are read in from a text file. In fact,
even if I got it to work I'm not sure I could use it be-
cause of the 'e' there (I'm concerned about executing
malicious code). But still I wonder how I could get it to
work in the example below (where a small here-document
replicates the external text file):

my $example = 'I saw Bob and Alice';

my $user_subs =<<'EOF';
/I saw (.*) and (.*)/I saw $2 and $1/
/I saw (.*) and (.*)/$1 and $2 saw me/
EOF

my @user_subs = split (/\n/, $user_subs);

my @substitutions;
foreach my $user_sub (@user_subs) {
$user_sub =~ s/^\///;
$user_sub =~ s/\/$//;
my ($match, $replace) = split (/\//, $user_sub);
my $pattern = {};
$pattern->{match} = $match;
$pattern->{replace} = $replace;
push @substitutions, $pattern;
}

foreach my $pattern (@substitutions) {
my $match = $pattern->{match};
my $replace = $pattern->{replace};
$example =~ s/$match/$replace/ee;
}

print "$example\n";
 
B

Brian McCauley

Bob said:
Each "e" causes the replacement to be evaluated as a Perl expression, as
in eval(), rather than be treated as a double-quoted string. If there
are two e's, the replacement is simply evaluated twice.

It's not nearly as simple as you might think.

A single /e qualifier does not involve any eval() in the sense the it
does not involve any run-time compilation of code. The code yyy is
compiled at compilation time.

Indeed...

s/xxx/yyy/e;

.... should be really be considered as more primatve than...

s/xxx/yyy/;

The s///e operator can be seen as a function that takes two arguments,
the first being a regex and the second a block of code that is evaluated
to find the replacement.

The s/// operator without the /e modifier is the same but the block is
implicitly enclosed a qq() operation (but with a delimiter outside the
real character set).

So...

s/xxx/yyy/e; # The most primative form

s/xxx/yyy/; # Same as s/xxx/qq(yyy)/

s/xxx/yyy/ee;# Same as s/xxx/eval(yyy)/
 
T

Tad McClellan

I've never seen 'ee' at the end of a substitution before.
It's contained in an example in perlop but without any
explanation as far as I can find.


Options are:

e Evaluate the right side as an expression.
g Replace globally, i.e., all occurrences.
i Do case-insensitive pattern matching.
m Treat string as multiple lines.
o Compile pattern only once.
s Treat string as single line.
x Use extended regular expressions.

....

A C</e> will cause the
replacement portion to be treated as a full-fledged Perl expression
and evaluated right then and there. It is, however, syntax checked at
compile-time. A second C<e> modifier will cause the replacement portion
to be C<eval>ed before being run as a Perl expression.
 
B

Ben Morrow

Quoth Brian McCauley said:
The s///e operator can be seen as a function that takes two arguments,
the first being a regex and the second a block of code that is evaluated
to find the replacement.

The s/// operator without the /e modifier is the same but the block is
implicitly enclosed a qq() operation (but with a delimiter outside the
real character set).

So...

s/xxx/yyy/e; # The most primative form

s/xxx/yyy/; # Same as s/xxx/qq(yyy)/ ^e

s/xxx/yyy/ee;# Same as s/xxx/eval(yyy)/
^e

(I know *you* know that, of course... :)

Nice explanation. I hadn't thought of it like that.

Ben
 

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,164
Messages
2,570,898
Members
47,439
Latest member
shasuze

Latest Threads

Top