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

I want to pass an entire s/foo/bar/i regexp substitution into a method as a (preferrable single) parameter.

#This works my $s = "This is a test"; my $rex = qr/test/i; print "yep\n" if($s =~ $rex); #How do I do this? $rexSubstitution = qr/test/TEST/i; $s =~ $rexSubstitution;

Can that be done, or do I need to evaluate a string at each match? A little searching tells me to go with the string approach.

/J

Replies are listed 'Best First'.
Re: qr and substitution
by Aristotle (Chancellor) on Oct 13, 2003 at 17:40 UTC
    You have to pass the substitution string separately. If that's really an issue, you might consider passing a closure instead, so that it would read something like:
    sub foo { my ($massage) = @_; local $_ = get_data_from_some_source(); $massage->(); } foo(sub { s/(foo|bar|baz)/\U$1/g });
    That may or may not work in your case. The problem you'll run into with passing a string is that you can't use the match variables in it and have them interpolated later - you'd have to do something like
    sub foo { my ($rx, $subst_e) = @_; local $_ = get_data_from_some_source(); s/$rx/eval $subst_e/ge; # short form: # s/$rx/$subst_e/gee; } foo(qr/(foo|bar|baz)/, '\U$1');
    You must trust the passed arguments in either case (both the closure as well as the string expr passed could do anything).

    Makeshifts last the longest.

      For now my immediate need is to just remove anything matched, i.e. do a s/$something_dynamic// . I hoped it would be trivial to do the fancy thing (replace it) but since it isn't, I'll just do the simple thing until I need more.

      Thanks.

      /J

Re: qr and substitution
by bart (Canon) on Oct 13, 2003 at 22:33 UTC
    I want to pass an entire s/foo/bar/i regexp substitution into a method as a (preferrable single) parameter.

    Can that be done?

    No, I don't think so. In your place, I'd pass two things: a qr// regexp, and a code ref for the substitution part.
    sub foo { my($qr, $replace) = @_; s/$qr/$replace->()/ge; } $_ = "This is a new dawn."; foo(qr/(\w+)/, sub { ucfirst $1 }); print;
    This makes use of the fact that $1 etc. are (localized) global variables.

    Alternatively, pass just a code ref for the whole s/// statement, as a callback. This callback can do more than just a substitution, though.

    sub bar { my $callback = shift; $callback->(); } bar(sub { s/(\w+)/\u$1/g; });
Re: qr and substitution
by Roger (Parson) on Oct 14, 2003 at 00:43 UTC
    Just a little comment that you can use embedded pattern match modifiers in your regular expression.

    $pattern = "foobar"; if ( /$pattern/i ) { } # equivalent to the more flexible form of $pattern = "(?i)foobar"; if ( /$pattern/ ) { }
Re: qr and substitution
by davido (Cardinal) on Oct 13, 2003 at 18:32 UTC
    Perhaps this snippet can be made to do what you want.

    use strict; use warnings; my $string = "This is a test."; my $re = "s/test/TEST/i"; eval "if( \$string =~ $re ) { print qq/Yep\n/; }"; warn $@ if $@; print $string, "\n";

    qr// allows you to pass the meat of a regular expression around compiled within a scalar variable. qr// doesn't allow for the regexp quotish operators to be embedded within (as in qr[s///].... that doesn't work), because it is not intended to contain any kind of code except for the meat of a regexp. If you want to pass a piece of actual code around as though it were a string, the way to execute the string is to eval it.

    As Aristotle pointed out, you always have to think carefully when you pass quotes or quote-like operators within a quoted string. But if you ask how to do a tricky thing, you get a tricky solution. ;) eval is never for the faint of heart. As Aristotle points out, it's safer and cleaner to pass a code ref rather than stringified code.


    Dave


    "If I had my life to do over again, I'd be a plumber." -- Albert Einstein
      If you do it this way, you have to be very careful with the contents of $re - you have a quoting context in the s/// which is defined within a quoting context, so for s!\\!/!g you'd have to pass 's!\\\\!/!g'. It's much easier to screw up this way than by passing a subref or a compiled RE and a string to eval in the right side of an s///ee;.

      Makeshifts last the longest.