in reply to How to eval a tr/// (was: Transliteration!!!)

There may be a better way, but when ive needed to do this ive used something like:
use strict; use warnings; sub make_tr { my $from=quotemeta(shift); my $to =quotemeta(shift); (my $opts=shift || "")=~tr/cdsCDS/cdscds/d; my $tr=eval "sub { (defined \$_[0] ? \$_[0] : \$_)=~tr/$from/$ +to/$opts}"; die "$@" if $@; return $tr; } my $tr=make_tr('A-Z','a-z'); my $x="YaBaDaBaDo"; $tr->($x); print $x,"\n"; $_="FOO"; $tr->(); print; __END__ yabadabado foo
Which returns a subroutine that can do the desired translation on the fly. Note that it works on $_ if a parameter isnt supplied, and returns the same thing that tr/// would. Itll die if the eval fails.

Good Luck.

update Forgot the quotemeta() on the first post... And beefed up the $opts cleaning... And added the my()s that are in my local version but not in the original. Sigh.

--- demerphq
my friends call me, usually because I'm late....

Replies are listed 'Best First'.
Re^2: Transliteration!!!
by Aristotle (Chancellor) on Oct 20, 2002 at 20:36 UTC
    That looks nice, but I'd add a couple details if I were to use it:
    sub make_tr { my ($from, $to, $opts) = map defined && quotemeta, @_; $opts = "" unless defined $opts; return eval "sub { (defined \$_[0] ? \$_[0] : \$_) =~ tr/$from/$to/$opt +s }" or die $@; }
    Remember to be very careful with any input to eval EXPR.

    Makeshifts last the longest.

      Heh. Good catch. And to be honest I posted the update before i read your reply... :-) And yours is more idomatic. Cool. :-)

      --- demerphq
      my friends call me, usually because I'm late....

        Thank's for the response. It works; of course!, but why? I guess I'm what you might call an intermediate programmer and I like to understand what's going on; so let me ask a couple of questions.

        1. I've never seen "quotemeta(shift)". I use local($from,$to,$opts) = @_;
        2. What is ($opts=shift || "")=~tr/cdsCDS/cdscds/d; doing?

        3. Help me understand how this works
          my $tr=eval "sub { (defined \$_[0] ? \$_[0] : $_) =~tr/$from/$to/$opts}";
        4. What happens if the ( die "$@" if $@ ) is simply left out and the eval fails.