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

So I ask the user for a regexp and a substitution string as parameters
perl -s -e "$data='abcdef'; $data=~s#$r#$s#; print $data" -- -r=(abc) -s=$1hello
produces
$1hellodef
I'd rather it produce
abchellodef
Adding an eval
perl -s -e "$data='abcdef'; eval qq{\$data=~s#$r#$s#}; print $data" -- -r=(abc) -s=$1hello
does the trick, but uses eval. Seems like it would be nice to have an option to "reinterpolate" a string. Am I missing another way to do this? I suppose, with block interpolation "${\func()}" that interpolation isn't any safer than eval, but it would be easier to use... especially if it were a substitution operation modifier s///R like e, possibly usable more than once s///RRR And yes, I could force the user to write it as code, and use s///e, but that is cumbersome for the user:
perl -s -e "$data='abcdef'; $data=~s#$r#$s#ee; print $data" -- -r=(abc) -s=$1.'hello'
Might be nice to have qR{$foo} that would do the interpolation of qq{$foo} and then reinterpolate. And maybe qRRR{$foo} for 3 reinterpolations...

The solution

Anonymous Monk's suggestion of String::Interpolate seems to suffice:

perl -s -MString::Interpolate -e "$data='abcdef'; $data=~s#$r#$s#; $data = String::Interpolate->interpolate( $data ); print $data" -- -r=(abc) -s=$1hello

Replies are listed 'Best First'.
Re: reinterpolation of regexp (and strings?)
by Anonymous Monk on Jul 23, 2008 at 07:30 UTC
Re: reinterpolation of regexp (and strings?)
by codeacrobat (Chaplain) on Jul 23, 2008 at 07:00 UTC
    Are you aware of the eval modifier? s/pattern/replacement/e

    print+qq(\L@{[ref\&@]}@{['@'x7^'!#2/"!4']});
      Its still EVAL not reinterpolate :)
        No, it's not. No variable's content is executed. /e is not like eval EXPR. (/ee, on the other hand...)
Re: reinterpolation of regexp (and strings?)
by ikegami (Patriarch) on Jul 23, 2008 at 07:33 UTC

    but that is cumbersome for the user

    Presuming the code will end up in a script,

    perl -s -e "$data='abcdef'; $data=~s#$r#qq{$s}#ee; print $data" -- -r= +(abc) -s=$1hello

    Note that the caller is able to execute arbitrary code, but that goes in hand in hand with what you asked. You'd need some kind of template system to be safe. (Upd: An anonymous monk has provided some.)

      It's the running arbitrary code part that worries me a little bit.

      However in the stuff mentioned by Anonymous Monk the use re 'eval' pragma is being used. I guess in God we trust;-)

        I don't see use re 'eval'; in String::Interpolate, for starters.

        And there's nothing wrong in use re 'eval'; per say. It's sometimes required to execute dynamically built regexps. I've used it a few times, and none of them involved executing untrusted code.

Re: reinterpolation of regexp (and strings?)
by rovf (Priest) on Jul 23, 2008 at 07:15 UTC
    $data=~s#$r#$s#

    How about

    $data=~s#$r#$s#e
    ?

    -- 
    Ronald Fischer <ynnor@mm.st>
      No, that will treat $s as a Perl expression, which will return its value, exactly like $data=~s#$r#$s#.
Re: reinterpolation of regexp (and strings?)
by dHarry (Abbot) on Jul 23, 2008 at 07:49 UTC

    Tricky. I don't think you can do it without the eval. Unless the /ee option does the trick as ikegami suggests.

    I ran into a similar problem and had to use eval. I am very much interested if there is another way of doing this. Your suggestion of re-interpolation sounds nice but is probably very tricky to implement.

      Tricky. I don't think you can do it without the eval. Unless the /ee option does the trick as ikegami suggests.

      s/.../.../ee is short for s/.../eval .../e, so that "unless" is not an exception.

      Your suggestion of re-interpolation sounds nice but is probably very tricky to implement.

      It's not possible since interpolation involved executing arbitrary code. Maybe a limited form of interpolation? That would be possible and useful.

        Are you aware that _any_ string interpolation can inject _any_ arbitrary code in a string? Try this:
        perl -le 'print qq(@{[ do{ print q(I got here first); 1 } ]})'
        The thing is: there is no safe string interpolation, you you might as well do the //ee thingy. :-)
        []s, HTH, Massa (κς,πμ,πλ)
      I'm not sure of the overhead involved in String::Interpolate, but it sure is easy to code and use. And lots of options for different types of interpolation, which makes me wonder if there is more overhead than needed....

      a qi{} operator could probably handle the simple case of interpolation without overhead, except on the part of the porters to code it...