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

I am writing a script, which gets the two parts of a s/// operand as parameters "$search" and "$replace". $search is treated with qr// and works. But later I want to do a substitution like
$value = s/$search/$replace/;
This works fine, as long I have a string stored in $replace. But I need capturing and then it fails, it inserts a '$1' instead of the value. If I just do a
m/$search/; print $1;
I get the desired result in '$1'.
I tried it with eval{} but had no luck.

Can anybody point me to the solution?

For example I want to find single digit numbers and give them a leading zero. These are embedded in a varying string. So it could be something like

my $search = qr/No\s+(\d)$/; my $replace = 'No 0$1'; $title =~ s/$search/$replace/;

And it came to pass that in time the Great God Om spake unto Brutha, the Chosen One: "Psst!"
(Terry Pratchett, Small Gods)

Replies are listed 'Best First'.
Re: Variable substitute and capturing
by ikegami (Patriarch) on Jan 16, 2006 at 16:46 UTC
    This has been discussed many times, most recently in this thread.
      Thank You for the pointer. The art of searching needs the ability to find right keywords, and I missed them, at least $1. Please excuse my duplicate questions.

      My problem was due to the missing escape of the $1 or the double eval, though the template idea sounds interesting. I never thought about using it without a template(-file).

      Thank You all for the lesson.

      And it came to pass that in time the Great God Om spake unto Brutha, the Chosen One: "Psst!"
      (Terry Pratchett, Small Gods)

Re: Variable substitute and capturing
by davidrw (Prior) on Jan 16, 2006 at 16:44 UTC
    I'm sure this is not the best (or even a good) approach, but it works.. hopefully a more decent answer will come up soon...
    eval "\$title =~ s/$search/$replace/";

      That won't work, since you didn't escape $search or $replace. Also, you're needlessly recompiling $search if it's already compiled. Use the following instead:

      $escaped_replace = '$1 (\$1.00)'; # Escape \, $, @ and / eval "\$title =~ s/\$search/$escaped_replace/";

      But since the only thing that needs to be compiled is the replace expression (not the entire substitution), the following is even better:

      $quoted_replace = '"$1 (\$1.00)"'; # Escape \, $, @ and /. Add quotes $title =~ s/$search/eval $quoted_replace/e;

      Of course, not using eval EXPR would be even better. In other words, a templating system would be even better. I mentioned this and posted an example in the thread to which I linked in my other post.

      Update: Added "or $replace".

      Update: Oops, davidrw is correct. $search doesn't need escaping.

        It did work .. i'm guessing cause $search is from qr// ..
        use strict; use warnings; my $s = "foobar"; my $search=qr/(foo)(bar)/; my $replace="\$1-\$2"; my $perl = "\$s =~ s/$search/$replace/"; warn $perl; eval $perl; print $s; __OUTPUT__ $s =~ s/(?-xism:(foo)(bar))/$1-$2/ at -e line 1. foo-bar
        I guess escaping $search is better though so that each eval call is dynamic on both ends (search & replace)..

        Also, i had tried the other way, but got an output of "0" instead of "foo-bar":
        perl -le '$s = foobar; $search=qr/(foo)(bar)/; $replace="\$1-\$2"; $s +=~ s/$search/eval $replace/e; print $s'
Re: Variable substitute and capturing
by Errto (Vicar) on Jan 16, 2006 at 23:25 UTC
    One time when this came up I devised my own solution which I posted here. I like it because it doesn't use eval EXPR, and lets you specify the regexp however you want including modifiers.