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

How can I use a variable($x) in statement like tr/$x/$x/ ? Do I use tr/\$x/\$x/ ? Somethine else? I tried it, but it doesn't work... Please save a newbie's life.... please

Replies are listed 'Best First'.
Re: tr/// statement
by lestrrat (Deacon) on Jul 19, 2001 at 11:06 UTC

    I t clearly says on perlop that tr/// does not interpolate, since the search list is created at compile time. So instead, you would need to do

    eval "tr/$var1/$var2/"; if( $@ ) { ## handle error }
      Could you please give me some more help on this tr/// statement?
      Could you please tell me if there is any improvement I should do? I use something like this:
      @letter = qw( a b c w x y ); for ($n=0; $n<6; $n++){ $x = $letter[$n]; $m = 0; open (DATA, "data.txt") || die "Could not open source data file."; while (<DATA>) { $cnt = eval "tr/$x/$x/"; $m += $cnt; } print "$x $m"; }
      data.txt contains lines like:
      aedj dfas jijiojsdf dsfwfy jiox jiohjdfax jojojdjj, oiiia oioje asfdc oujsdfayx soujfosdxjpoiojfdxjljojaois jojojx jopjpx jojoijx joijiodfx

      asdfasdf jjalsdf jlajkldf jojiojsd jiojasj ioj wwdn jojae jojocjoc joijss jiojwx jiojoxuiojy joiyu oiuouyy

        This is unrelated to your tr/// problem but I would suggest using:

        foreach $x (@letter) {

        instead of your for loop, that way you don't have to remember to change the loop termination value from 6 if you change the number of letters.

        Kevin O'Rourke

        I'd rather not open and close the file more than once: disk accesses take time (there's the cache, you didn't mention your file's size). Instead, I would first generate subs that count a given character and store them in a hash, referenced by that character.

        Then, for each line in the file, loop over the letters and call the sub from the hash. Increment a counter which is itself stored in a hash.

        #!/usr/local/bin/perl use strict; my @letter = qw/ a b c x y z /; my %subs; my %counts; foreach ( @letter ) { $subs{$_} = eval "sub { \$_[0] =~ tr/$_// }"; } while ( <DATA> ) { foreach my $letter ( @letter ) { $counts{$letter} += $subs{$letter}->($_); } } print "$_: $counts{$_}\n" foreach @letter; __DATA__ aedj dfas jijiojsdf dsfwfy jiox jiohjdfax jojojdjj, oiiia oioje asfdc +oujsdfayx soujfosdxjpoiojfdxjljojaois jojojx jopjpx jojoijx joijiodfx asdfasdf jjalsdf jlajkldf jojiojsd jiojasj ioj wwdn jojae jojocjoc joi +jss jiojwx jiojoxuiojy joiyu oiuouyy

        --bwana147

        Hi,
        I'd write the whole thing as:
        @letter = qw/a b c w x y/; foreach $x (@letter) { $m = 0; open(DATA,"data.txt") or die "couldn't open data\n$!"; while (<DATA>) { $m += ($_ =~ s/$x/$x/g); } close(DATA); print "count $x = $m\n"; }
        (note the use of foreach, or and $! ...)

        Regards... Stefan

        If you just want letter counts, you could do something like this (though I have a hard time believing this is not homework):
        my $letters = "abcwxy"; my $re = qr/[$letters]/; my $cnt; while (<INPUT>) $cnt++ while /$re/g; } print "$cnt\n";
      Thanks for your help! Appreciated!!
Re: tr/// statement
by Zaxo (Archbishop) on Jul 19, 2001 at 11:09 UTC
    tr///doesn't interpolate like s/// or m//, as you've seen. You can get the effect you want with:

    eval "tr/$x/$y/";

    The double quotes get variables interpolated before the expression is evaluated.

    After Compline,
    Zaxo

      Thanks a million! :)