Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re: Precompiling substitution regex

by wind (Priest)
on Jun 17, 2011 at 22:49 UTC ( [id://910267]=note: print w/replies, xml ) Need Help??


in reply to Precompiling substitution regex

Use eval to cache the substitution in an anonymous sub:

use strict; use warnings; # Cached Regex's: LHS, RHS, Modifiers my @re_rules = ( ['(?:this|or|that)', 'bob', 'gsi'], ['(?:One|Two|Three)', 'Four', 'gs'], ); my @re_subs = map { my $sub = eval "sub { s/$_->[0]/$_->[1]/$_->[2] for (\@_)}"; die $@ if $@; $sub; } @re_rules; my @strings = ('this one or that other', 'One two Three'); for my $string (@strings) { $_->($string) for (@re_subs); print "$string\n"; }
Or just declare the anonymous subs yourself if you don't need the special markup:
use strict; use warnings; my @re_subs = ( sub { s/(?:this|or|that)/bob/gsi for (@_) }, sub { s/(?:One|Two|Three)/Four/gs for (@_) }, ); my @strings = ('this one or that other', 'One two Three'); for my $string (@strings) { $_->($string) for (@re_subs); print "$string\n"; }

Replies are listed 'Best First'.
Re^2: Precompiling substitution regex
by AnomalousMonk (Archbishop) on Jul 26, 2019 at 13:24 UTC

    FWIW, note that in the second example here, the outer for-loop is not needed:

    c:\@Work\Perl\monks>perl -wMstrict -le "my @re_subs = ( sub { s/(?:this|or|that)/bob/gsi for @_ }, sub { s/(?:One|Two|Three)/Four/gs for @_ }, ); ;; my @strings = ('tHiS one or ThAt other', 'One two Three'); printf qq{'$_' } for @strings; print ''; ;; $_->(@strings) for @re_subs; printf qq{'$_' } for @strings; print ''; " 'tHiS one or ThAt other' 'One two Three' 'bob one bob bob other' 'Four two Four'
    That's because of aliasing through the  @_ function argument array. Actually, the work of the outer for-loop is just being moved to the for-loop within each anonymous subroutine, which is now given something to loop over whereas before it was just being used for topicalization.


    Give a man a fish:  <%-{-{-{-<

Re^2: Precompiling substitution regex
by FreakyGreenLeaky (Sexton) on Jun 18, 2011 at 09:46 UTC
    Thanks. Does the second sample pre-compile the regexes?

      I believe that we're mixing terminology here, as "pre-compile" isn't exactly what you're wanting to ask. Yes, the code is only compiled once and after that point it will not need to be recompiled.

      I've used this type of mechanism to program configurable filters. Letting a user edit a config file where they specify anonymous subs like that which are later eval'd and used in my larger package.

Re^2: Precompiling substitution regex
by Anonymous Monk on Oct 14, 2015 at 06:35 UTC
    old thread but wanted to ask what
    my $sub =eval "sub { s/$_->[0]/$_->[1]/$_->[2] for (\@_)}";
    does and what would be different if eval was removed?

      In an eval evironment in which  @_ was, e.g.,
          @_ = ('searchPattern', 'replacementString', 'regexModifiers');
      (presumably, the eval statement is called in the context of a function to which arguments were passed via @_), the eval would return a code reference equivalent to
          sub { s/searchPattern/replacementString/regexModifiers for @_ }
      which would allow one to iterate over a list of strings and do substitutions on each (non-literal!) string:

      my $x = 'some'; my $y = 'strings'; my $z = 'here'; $sub->($x, $y, $z);

      The only benefit that I can see of using the string eval is that the regex | substitution operator modifiers  /g /e /r and perhaps a couple others cannot be "passed" in any other way. If not for these modifiers, one could simply write something like (again, assuming this is in a function in which  @_ held search/replace strings)
          my $sub = sub { s/$_->[0]/$_->[1]/xmsg for @_ };
          ...
          $sub->($x, $y, $z);
      (note the literal modifier group) and get the same result. In this example, the modifiers other than  /g could be passed in a string.

      Update: E.g.,

      c:\@Work\Perl\monks>perl -wMstrict -le "S('(?xmsi) foo', 'bar', 'g'); ;; sub S { my $sub = eval qq{ sub { s/$_[0]/$_[1]/$_[2] for \@_ } }; ;; my $x = 'foo'; my $y = 'Foo fOo foO'; my $z = 'FOO'; ;; $sub->($x, $y, $z); print qq{x '$x' y '$y' z '$z'}; } " x 'bar' y 'bar bar bar' z 'bar'
      And yes, this is a trick for a completely trusted environment. But then: "Trust, but verify!"


      Give a man a fish:  <%-{-{-{-<

        Speaking of evaling substitution into existence, if you trust the OP to specify the regex and substitution string, and you're not validating those strings

        you might as well switch the interface/api to needing subs , so the user specifies the whole sub instead of parts to build one

        on the other hand, String::Interpolate/String::Interpolate::RE

      what do you observe happening when you remove eval?

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://910267]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (1)
As of 2024-04-25 00:41 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found