in reply to eval routines for faster regexp: how-to...

1/ Using a string eval to speed-up is non sense. String eval means that you must recompile each time you hit the eval at run-time.

2/ you code is basically:

sub { return 1 if m!foo!o; return 0 }

this can be simplified to

 sub { m!foo!o }

Not only this returns a boolean value but at no extra cost the list of strings matched in parenthesis if there are like the rest of your post implies. In that later case, the boolean value is obtained indirectly because in scalar context, the list is converted to its length. This leads me to 3/

3/ now about $match = qq@  return (\$1,\$2) if m!(foo)(bar)!; @; As I said the match operator returns directly the list of matches so you don't need to return explicitely $1, $2...

I really don't understand what you want to do. But I am sure your way of doing it is certainly incorrect.

Edited: suppressed inaccurate remarks. Thanks to chipmunk for pointing out my mistakes.

-- stefp

Replies are listed 'Best First'.
Re: Re: eval routines for faster regexp: how-to...
by chipmunk (Parson) on Nov 08, 2001 at 08:40 UTC
    A few comments... Using string eval to compile an anonymous subroutine created at runtime is not necessarily nonsense. The eval is only executed once; the subroutine can be called many times. Here's a better example, using tr///, for which the search and replace lists have to be defined when the tr/// is compiled:
    #!/usr/local/bin/perl sub make_tr { my($search, $replace, $flags) = @_; $flags = '' if not defined $flags; my $code = "sub { \$_[0] =~ tr/$search/$replace/$flags }"; my $sub = eval $code; die "$code\n$@" if $@; return $sub; } my $rotate = shift; $rotate = 13 unless defined $rotate and $rotate =~ /^\d+\z/; $rotate %= 26; $replace = chr(ord('A')+$rotate) . '-ZA-' . chr(ord('A')+$rotate-1); $replace .= lc($replace); my $rotate_sub = make_tr('A-Za-z', $replace, ''); while (<>) { $rotate_sub->($_); print; }
    Instead of calling eval every time through the loop, eval is called once ahead of time and an anonymous subroutine is called inside the loop. (Another way to avoid repeated calls to eval would be to wrap the whole loop in an eval.)

    You're absolutely right that the original poster's code is equivalent to sub { return 1 if m!foo!o }. Not a very useful application of eval. :) If foo were actually a variable, it would make a tiny bit more sense: eval "sub { return 1 if m!$foo!o }. But as japhy already noted, qr//, rather than eval, should be used for that.

    A final aside, in $match = qq@ return (\$1,\$2) if m!(foo)(bar)!; @;, those backslashes are actually escaping the dollars signs from interpolation, rather than creating references. It's a double-quoted string.

      BTW, you can also use eval to make subs (rather than references to subs), which is what I do quite often if I have a lot of matches to find:

      sub genFind { my $patt = shift; my $code = "sub find {\n\tmy \$str = shift;\n\t\$str =~/$patt/;\n}; eval $code; die "Error in eval: $@\ncode = $code\n" if $@; } #call genFind ('foo'); $res = find ('barefoot'); #can now call 'find' as function
      The nice thing about this is that looks just like a normal function and you don't have to worry about '&' and stuff.

      pike

        You don't really need the "\n" and "\t"s in there. If you're really after readability consider using a heredoc which will let you actually format the code readably.

        my $code = <<EOSUB; sub find { my \$str = shift; \$str =~/$patt/; } EOSUB