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

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.

Replies are listed 'Best First'.
Re: Re: Re: eval routines for faster regexp: how-to...
by pike (Monk) on Nov 08, 2001 at 14:27 UTC
    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