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

I want to implement a function that accepts a qr/Regexp/ and a string. The regexp is going to be matched against another string and, after that, I want to interpolate any backreferences contained in the string argument. I thought about evaluating the string in an eval, but it seems that the capture buffers aren't available in the eval context. As an example of what I'm attempting to do, take the following code:
#!/usr/bin/perl if ('abc' =~ qr/a(.)c/) { print "a$1$1c", "\n"; } sub expand { my ($rx, $from, $to) = @_; if ($from =~ $rx) { print eval {$to}, "\n"; } } expand(qr/a(.)c/, 'abc', 'a$1$1c');
I'd like it to output two identical lines:
abbc abbc
However, it actually doesn't interpolate the backreferences in the eval and output this:
abbc a$1$1c
Any suggestion would be appreciated.

Replies are listed 'Best First'.
Re: Interpolating backreferences in an eval
by ikegami (Patriarch) on Feb 11, 2009 at 17:17 UTC
    'a$1$1c' is a template. You need a template module that understands that format. String::Interpolate should do the trick.
    use String::Interpolate qw( ); sub expand { my ($rx, $from, $to) = @_; if ($from =~ $rx) { my $t = String::Interpolate->new(); $t->($to); $t->([ map substr($from, $-[$_], $+[$_] - $-[$_]), 1..$#- ]); print "$t\n"; } }

    It's close to Perl code ('"a$1$1c"') so you could convert it to Perl code (the step you are missing) and execute it (eval $code), but that's a very bad approach.

Re: Interpolating backreferences in an eval
by gone2015 (Deacon) on Feb 11, 2009 at 17:11 UTC


    print eval qq{"$to"}, "\n";
    ...eval comes in two flavours: (a) eval BLOCK -- in which the BLOCK is compiled in the usual way, and the eval is a way of trapping die; (b) eval EXPR in which the result of the EXPR is parsed and executed at run time. See expr.

    Of course, you could also:

    my $q = $1 ; $to =~ s/\$1/$q/g ;

      Thanks you! It works.

      I've tried eval "$to" but got a syntax error that I couldn't understand. Seeing that eval qq{"$to"} is the same as eval "\"$to\"" I can understand now what I've done wrong.

Re: Interpolating backreferences in an eval
by repellent (Priest) on Feb 11, 2009 at 20:17 UTC
    eval's are evil. Templates are the way to go. How would you account for:
    expand(qr/a(.)c/, 'abc', 'a$1${ print \\"haha! lets do something else +...\n\\"; 1 }c');

    At least it was nice enough to give you your "abbc" :)
Re: Interpolating backreferences in an eval
by AnomalousMonk (Archbishop) on Feb 12, 2009 at 06:00 UTC
Re: Interpolating backreferences in an eval
by Anonymous Monk on Feb 11, 2009 at 17:23 UTC
    sub expand { my ($rx, $from, $to) = @_; if ($from =~ /$rx/) { print (eval $to)."\n"; } } #expand(qr/a(.)c/, 'abc', 'a$1$1c'); expand('a(.)c', 'abc', "a$1$1c");

      For it to run, that should be

      expand(qr/a(.)c/, 'abc', '"a$1$1c"');


      print (eval qq{"$to"})."\n"; expand(qr/a(.)c/, 'abc', 'a$1$1c');

      But oh so wrong.