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

Hi monks,

This seems like it should be straightforward, but I'm clearly missing something.I'm trying to iterate over lists of substituion REs, and the substitutions aren't substituting.

I have something like (heavily simplified):

%regexes = (first => ['(\w+) (\w+) (\w+)', '$1 $3'], second => ['and so on', 'and on'] ); my $string = "big hairy mess"; foreach my $re (keys %regexes) { $string =~ s/$regexes{$re}[0]/$regexes{$re}[1]/i; print "$re: $string\n"; }
The 'first' regex, instead of printing 'first: big mess' prints 'first: $1 $3'.

I've tried adding the /e switch, which didn't help, and wrapping the backreferences in (?{}) blocks, which didn't help.

I'm sure I'm missing something stupid, but can't figure out what that might be. Hints?

Replies are listed 'Best First'.
Re: Storing substitution patterns
by Abigail-II (Bishop) on Feb 11, 2004 at 15:07 UTC
    Adding /e tells perl to treat the replacement part as code, and execute it. The code is $regexes{$re}[1]. If you "execute" that, you get the same as you would interpolate it - you get $1 $3. What you want is to execute that. To do so, tag /ee (double execution) at the end, not just a /e.

    Abigail

      D'oh. Abigail is entirely correct. Though you will need to change '$1 $3' to something like 'qq($1 $3)' or '"$1 $3"'.

      That was it! Thanks, Abigail. You're the best.

      (Didn't know one could specify /ee... that gives me all sorts of evil ideas...)

Re: Storing substitution patterns
by Fletch (Bishop) on Feb 11, 2004 at 15:07 UTC
    sub mksub (&) { my $sub = shift; return sub { local( $_ ) = $_[0]; $sub->(); $_[0]=$_ }; } %regexes = ( first => mksub { s/(\w+) (\w+) (\w+)/$1 $3/ }, second => mksub { s/and so on/and on/ }, ); my $string = "big hairy mess"; for my $re ( keys %regexes ) { $regexes{ $re }->( $string ); print "$re: $string\n"; }
Re: Storing substitution patterns
by duff (Parson) on Feb 11, 2004 at 14:57 UTC

    Strange. I would have thought that the /e modifier would do what you want. You can always wrap the entire substitution in an eval like so:

    eval "\$string =~ s/$regexes{$re}[0]/$regexes{$re}[1]/i";
Re: Storing substitution patterns
by Hena (Friar) on Feb 11, 2004 at 14:49 UTC
    Hmm, my quess would be to make a following change
    # %regexes = (first => ['(\w+) (\w+) (\w+)', '$1 $3'], # second => ['and so on', 'and on'] ); # into %regexes = (first => ["(\w+) (\w+) (\w+)", "$1 $3"], second => ["and so on", "and on"] );
    This is untested, so i could be wrong.

      Nah, that will interpolate $1 and $3 into the string right then and there. That would be long before they are ever set in the substitution.