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

I wrote something like this:

$regex = ['foo','bar']; $string = 'blah foo blah'; $string =~ s/$regex->[0]/$regex->[1]/;
which worked just fine.

But then I wanted to use backreferences:

$regex = ['(foo)','bar$1']; $string = 'blah foo blah'; $string =~ s/$regex->[0]/$regex->[1]/;
which didn't. Not even with /e. Is this an old question? It's not in the FAQ.


($_='kkvvttuu bbooppuuiiffss qqffssmm iibbddllffss')
=~y~b-v~a-z~s; print

Replies are listed 'Best First'.
Re: Regex Substitution, Interpolating on the RHS?
by dave_the_m (Monsignor) on Jul 18, 2005 at 11:52 UTC
    my $repl = '"foo$1bar"'; $a = '12345'; $a =~ s/(23)/$repl/ee; print $a,"\n"; $ ./perl /tmp/p 1foo23bar45 $

    Dave.

      Wow. Interesting stuff. Double quotes, double-e... Thank you.


      ($_='kkvvttuu bbooppuuiiffss qqffssmm iibbddllffss')
      =~y~b-v~a-z~s; print

        You should realize this means you're building source code on the fly and evaling it. Its a serious security and correctness issue. The following is equivalent and makes the string-eval more visible than just the second /e would. The first /e is completely different in character than the second /e.

        s<$regex->[0]>{ eval qq["$regex->[1]"]; }e
Re: Regex Substitution, Interpolating on the RHS?
by Roy Johnson (Monsignor) on Jul 18, 2005 at 13:07 UTC
    Another approach to delayed evaluation is to use closures (update: ok, not really closures, but subroutines). To get a sub to be evaluated in the double-quotish context of a s/// replacement, it needs to be part of a block. The only block interpolated in double quotes is a deref.

    So you make the closure return a ref to the string you want, and deref it in the replacement. It will be evaluated at replacement time, and you get the substitution you're looking for.

    my $regex = ['(foo)',sub {\"bar$1"}]; my $string = 'blah foo blah'; $string =~ s/$regex->[0]/${$regex->[1]->()}/; print "S=$string\n";

    Caution: Contents may have been coded under pressure.
      That's very smart and I'm very grateful. Can I spoil all that for asking how I get a generalised solution where I can have the same code run both evaluated and non-evaluated regexes?

      How do I code, for instance, so that $regex may sometimes be:

      my $regex = ['(foo)',sub {\"bar$1"}];
      but at other times just
      my $regex = ['foo','bar'];

      I'm guessing I'll need to use ref() or something?



      ($_='kkvvttuu bbooppuuiiffss qqffssmm iibbddllffss')
      =~y~b-v~a-z~s; print
        Yes, you would check ref($regex->[1]). It will be 'CODE' for a coderef and false (empty) for a non-ref. You could put the whole test/selection into the block like so:
        my $regex = ['(foo)',sub {\"bar$1"}]; my $string = 'blah foo blah'; $string =~ s/$regex->[0]/${(ref($regex->[1]) eq 'CODE' ? $regex->[1]-> +() : \$regex->[1])}/; print "S=$string\n";

        Caution: Contents may have been coded under pressure.
Re: Regex Substitution, Interpolating on the RHS?
by jbrugger (Parson) on Jul 18, 2005 at 11:23 UTC
    try "bar$1"?


    update:
    Won't give an error but doesn't work...
    I assume you need the outpur blah barfoo blah like the regex: s/(foo)/bar$1/does...
    this created foo bar blah...

    weird thing is that the parentheses are evaluated correctly in the regex: this works:
    my $regex = ['(foo)','bar']; $string =~ s/$regex->[0]/$regex->[1]$1/;


    update2:
    dave_the_m was quicker and right, it's
    #!/usr/bin/perl use strict; my $regex = ['(foo)', '"bar$1"' ]; my $string = 'blah foo blah'; $string =~ s/$regex->[0]/$regex->[1]/ee; print "$string\n";
    "We all agree on the necessity of compromise. We just can't agree on when it's necessary to compromise." - Larry Wall.
A reply falls below the community's threshold of quality. You may see it by logging in.