nafion112 has asked for the wisdom of the Perl Monks concerning the following question:

Hi All!

I am trying to do a regex substitiution that is contained in a variable. For example, if I have:

$substitution = 's/this/that/';

I would like to do something like:

$candidate =~ ($substitution);

or

$candidate =~ s/($substitution)/;

or something like that. Both of those are obviously wrong, but you get the idea. I've been fooling around with every little syntax modification I can think of and nothing seems to work. Might there be a better way to go about this? (I cannot change the fact that I am given the actual substitution regex, complete with delimiters, in a scalar variable...)

Replies are listed 'Best First'.
Re: Substitution with regexes in variables
by ikegami (Patriarch) on Nov 15, 2009 at 00:07 UTC

    s/// is an operator, so that means your variable contains Perl code. eval EXPR can be used to execute it.

    But that's rather unsafe. I assume you don't want to allow arbitrary code execution (variable lookups, (?{}), (??{}) and /e). If so, you can use the following:

    my ($pat, $repl, $mods) = $substitution =~ m{ ^s/ ( (?:[^/\\]+|\\.)* ) / ( .* ) / ( [a-z]* ) \z }xs or die("Bad substitution\n"); my %mods = map { $_ => 1 } $mods =~ /./sg; my $global = delete($mods{g}); $mods = join('', delete(@mods{qw( i m s x )})) and $pat = "(?$mods:$pat)"; die("Unknown modifiers \"", keys(%mods), "\"\n") if %mods; no re 'eval'; if ($global) { $candidate =~ s/$pat/$repl/g; } else { $candidate =~ s/$pat/$repl/; }
      It is probably better to use Text::Balanced's extract_quotelike function rather than hand-rolling a substitution parser. (At least, the documentation suggests that it will handle s///'s correctly; and your code makes no effort to handle differently delimited patterns, among the (I assume) many other possible perversions.)

        That would allow other delimiters, but that would make it *more* complicated from a security standpoint. I didn't want to spend time thinking of the implications.

Re: Substitution with regexes in variables
by AnomalousMonk (Archbishop) on Nov 14, 2009 at 23:50 UTC
    If it is really true that you '... cannot change the fact that [you are] given the actual substitution regex, complete with delimiters, in a scalar variable...', then:
    >perl -wMstrict -le "$_ = 'this is a bad idea'; for my $substitution (@ARGV) { print qq{substitution: $substitution}; my $subs = eval $substitution; if ($@ or not defined $subs) { die qq{$substitution failed: $@}; } print; } " s/this/that/ "s/is/would be/" "s/(a)???/$1 very/" substitution: s/this/that/ that is a bad idea substitution: s/is/would be/ that would be a bad idea substitution: s/(a)???/$1 very/ s/(a)???/$1 very/ failed: Nested quantifiers in regex; marked by <-- HERE in m/(a)??? <-- HERE / at (eval 3) ...