Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Strange behaviour of tr function in case the set1 is supplied by a variable

by likbez (Sexton)
on Nov 16, 2017 at 02:50 UTC ( #1203542=perlquestion: print w/replies, xml ) Need Help??

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

Looks like in tr function a scalar variable is accepted as the fist argument, but is not compiled properly into set of characters
$str1='abcde'; $str2='eda'; print "Test 1: strait set\n"; $diff1=$str1=~tr/$str2//; $diff2=$str1=~tr/eda//; print " diff1=$diff1, diff2=$diff2\n"; print "Test 2: complement set\n"; $diff1=$str1=~tr/$str2//c; $diff2=$str1=~tr/eda//c; print " diff1=$diff1, diff2=$diff2\n";
This produces in perl 5, version 26:
Test 1: strait set diff1=0, diff2=3 Test 2: complement set diff1=5, diff2=2

Obviously only the second result in both tests is correct.

Looks like only explicitly given first set is correctly compiled.

Is this a feature or a bug ?

Replies are listed 'Best First'.
Re: Strange behaviour of tr function in case the set1 is supplied by a variable
by Athanasius (Archbishop) on Nov 16, 2017 at 03:08 UTC
Re: Strange behaviour of tr function in case the set1 is supplied by a variable
by roboticus (Chancellor) on Nov 16, 2017 at 03:08 UTC

    likbez:

    Feature, per the tr docs Characters may be literals or any of the escape sequences accepted in double-quoted strings. But there is no interpolation, so "$" and "@" are treated as literals. A hyphen at the beginning or end, or preceded by a backslash is considered a literal. Escape sequence details are in the table near the beginning of this section.

    So if you want to use a string to specify the values in a tr statement, you'll probably have to do it via a string eval:

    $ cat foo.pl use strict; use warnings; my $str1 = 'abcde'; my $str2 = 'eda'; my $diff1 = 0; eval "\$diff1=\$str1=~tr/$str2//"; print "diff1: $diff1\n"; $ perl foo.pl diff1: 3

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: Strange behaviour of tr function in case the set1 is supplied by a variable
by Anonymous Monk on Nov 16, 2017 at 03:09 UTC

    Looks like in tr function a scalar variable is accepted as the fist argument, but is not compiled properly into set of characters

    :)

    you're guessing how tr/// works, you're guessing it works like s/// or m///, but you can't guess , it doesn't work like that, it doesn't interpolate variables, read perldoc -f tr for the details

      you're guessing how tr/// works, you're guessing it works like s/// or m///, but you can't guess , it doesn't work like that, it doesn't interpolate variables, read perldoc -f tr for the details
      Houston, we have a problem ;-)

      First of all that limits tr area of applicability.

      The second, it's not that I am guessing, I just (wrongly) extrapolated regex behavior on tr, as people more often use regex then tr. Funny, but searching my old code and comments in it is clear that I remembered (probably discovered the hard way, not by reading the documentation ;-) this nuance several years ago. Not now. Completely forgotten. Erased from memory. And that tells you something about Perl complexity (actually tr is not that frequently used by most programmers, especially for counting characters).

      And that's a real situation, that we face with Perl in other areas too (and not only with Perl): Perl exceeds typical human memory capacity to hold the information about the language. That's why we need "crutches" like strict.

      You simply can't remember all the nuances of more then a dozen of string-related built-in functions, can you? You probably can (and should) for index/rindex and substr, but that's about it.

      So here are two problems here:

      1. Are / / strings uniformly interpreted in the language, or there is a "gotcha" because they are differently interpreted by tr (essentially as a single quoted strings) and regex (as double quoted strings) ?

      2. If so, what is the quality of warnings about this gotcha? There is no warning issued, if you use strict and warnings. BTW,it looks like $ can be escaped:

      main::(-e:1): 0 DB<5> $_='\$bba\$' DB<6> tr/\$/?/ DB<7> print $_ \?bba\?

      Right now there is zero warnings issued with use strict and use warnings enabled. Looks like this idea of using =~ for tr was not so good, after all. Regular syntax like tr(set1, set2) would be much better. But it's to late to change and now we need warnings to be implemented.

        Are / / strings uniformly interpreted in the language?
        // is an abbreviation for m// (be careful of context). But // is can be replaced by (almost?) any delimiter, by using m or s or tr.

        Quote-Like-Operators shows 2 interesting examples with tr:

            tr[aeiouy][yuoiea] or tr(+\-*/)/ABCD/.

        -QM
        --
        Quantum Mechanics: The dreams stuff is made of

Re: Strange behaviour of tr function in case the set1 is supplied by a variable
by ww (Archbishop) on Nov 16, 2017 at 03:16 UTC

    Same results in AS 5.24 under Win7x64.

    Suspected problem might have arisen from lack of strict, warnings. Wrong, same results BUT using both remains a generally good idea.

    Also wondered if compiling (with qr/.../) might change the outcome. Wrong again, albeit with variant (erroneous) output.

    Correct me if I'm wrong, guessing that "strait" is a typo or personal shortening of "straight."

    Update: Now that I've seen earlier replies... ouch, pounding forehead into brick wall!


    ďAh, you donít have to know everything. You just have to know where to find it.Ē John Brunner'
    If I've misconstrued your question or the logic needed to answer it, I offer my apologies to all those electrons which were inconvenienced by the creation of this post.
Re: Strange behaviour of tr function in case the set1 is supplied by a variable
by likbez (Sexton) on Nov 16, 2017 at 03:10 UTC
    With eval statement works correctly. So it looks like $ is treated by tr as a regular symbol and no warning are issued.
    $statement='$diff1=$str1'."=~tr/$str2//;"; eval($statement); print "With eval: diff1=$diff1\n";
    that will produce:
    With eval: diff1=3
    </code> 

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1203542]
Approved by ww
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others cooling their heels in the Monastery: (6)
As of 2021-05-16 12:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Perl 7 will be out ...





    Results (151 votes). Check out past polls.

    Notices?