Perl tr and ruby String#tr

This, in perl:
$str =~ tr/\0\200/\200\0/;

Produces a different result then this:

str.tr!("\0\200","\200\0")

How do I do this in ruby?

Input data? Output data? Expected results?

    robert

···

snacktime <snacktime@gmail.com> wrote:

This, in perl:
$str =~ tr/\0\200/\200\0/;

Produces a different result then this:

str.tr!("\0\200","\200\0")

How do I do this in ruby?

my $even_bits = "\0";
my $odd_bits = "\200";
foreach (0 .. 7) {
    $even_bits .= $odd_bits;
    $odd_bits = $even_bits;
    $odd_bits =~ tr/\0\200/\200\0/;
}
print unpack("c*","$odd_bits");

Output:
-12800-1280-128-12800-128-1280-12800-1280-128-1280-12800-128-12800-1280-128-12800-128-1280-12800-128-12800-1280-128-1280-12800-1280-128-12800-
128-1280-12800-1280-128-1280-12800-128-12800-1280-128-1280-12800-1280-128-12800-128-1280-12800-128-12800-1280-128-12800-128-1280-12800-1280-12
8-1280-12800-128-12800-1280-128-12800-128-1280-12800-128-12800-1280-128-1280-12800-1280-128-12800-128-1280-12800-128-12800-1280-128-12800-128-
1280-12800-1280-128-1280-12800-128-12800-1280-128-1280-12800-1280-128-12800-128-1280-12800-1280-128-1280-12800-128-12800-1280-128-12800-128-12
80-12800-128-12800-1280-128-1280-12800-1280-128-12800-128-1280-12800-128

even_bits = "\0"
odd_bits = "\200"
8.times do
  even_bits << odd_bits
  odd_bits = even_bits
  odd_bits.tr!("\0\200","\200\0")
end

print odd_bits.unpack('c*')

Output:
0-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-
1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-12
80-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280
-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1
280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-1280-128

- odd_bits = even_bits
+ odd_bits = even_bits.clone

= assigns reference to the object in this case

···

On 8/12/06, snacktime <snacktime@gmail.com> wrote:

even_bits = "\0"
odd_bits = "\200"
8.times do
  even_bits << odd_bits
  odd_bits = even_bits
  odd_bits.tr!("\0\200","\200\0")
end

print odd_bits.unpack('c*')

Ok now I feel stupid:) Thanks for pointing that out.

···

On 8/12/06, Jan Svitok <jan.svitok@gmail.com> wrote:

On 8/12/06, snacktime <snacktime@gmail.com> wrote:

> even_bits = "\0"
> odd_bits = "\200"
> 8.times do
> even_bits << odd_bits
> odd_bits = even_bits
> odd_bits.tr!("\0\200","\200\0")
> end
>
> print odd_bits.unpack('c*')

- odd_bits = even_bits
+ odd_bits = even_bits.clone

= assigns reference to the object in this case

Well, I looked at it for quite a long time before I realized what's
going on: at first I replaced your strings with 'A's and 'B's as these
are easier to recognize, then I tried 'AA-AB-BA-BB'.tr(...) and both
versions were ok. So it wasn't a tr problem. Soon after that the
inspiration came... :wink:

You're welcome.

J.

···

On 8/12/06, snacktime <snacktime@gmail.com> wrote:

On 8/12/06, Jan Svitok <jan.svitok@gmail.com> wrote:
> On 8/12/06, snacktime <snacktime@gmail.com> wrote:
>
> > even_bits = "\0"
> > odd_bits = "\200"
> > 8.times do
> > even_bits << odd_bits
> > odd_bits = even_bits
> > odd_bits.tr!("\0\200","\200\0")
> > end
> >
> > print odd_bits.unpack('c*')
>
> - odd_bits = even_bits
> + odd_bits = even_bits.clone
>
> = assigns reference to the object in this case
>
Ok now I feel stupid:) Thanks for pointing that out.

Ok almost there one more question on using tr. If the to_string is a
variable, what to do? In perl you would use eval because the
transliteration for the from_string and to_string are done at compile
time. Following is the perl code that produces the correct result,
and the ruby code which I can't get to produce the same output. Any
ideas on how to do this correctly in ruby?

$even_parity = '\0\201\202\3\204\5\6\207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\
245\246\47\50\251\252\53\254\55\56\2570\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\3
27\330YZ\333\134\335\336_\140\341\342c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377\0\201\202\3\204\5\6\207\
210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\245\246\47\50\251\252\53\254\55\56\2570\2
61\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ\333\134\335\336_\140\341\342c\34
4ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377';

eval <<EDQ;

sub setEvenParity {
    my(\@s) = \@_;
    foreach (\@s) {
        tr/\\0-\\377/$even_parity/;
    }
    wantarray ? \@s : join '', \@s;
}

EDQ
die $@ if $@;

$out = setEvenParity('s');
print $out;

@even_parity = '\0\201\202\3\204\5\6\207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\
245\246\47\50\251\252\53\254\55\56\2570\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\3
27\330YZ\333\134\335\336_\140\341\342c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377\0\201\202\3\204\5\6\207\
210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\245\246\47\50\251\252\53\254\55\56\2570\2
61\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ\333\134\335\336_\140\341\342c\34
4ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377';

eval <<EDQ

def setEvenParity(str)
  str.tr("\\0-\\377",@even_parity)
end

EDQ

out = setEvenParity('s')
print out

Ok almost there one more question on using tr. If the to_string is a
variable, what to do? In perl you would use eval because the
transliteration for the from_string and to_string are done at compile
time. Following is the perl code that produces the correct result,
and the ruby code which I can't get to produce the same output. Any
ideas on how to do this correctly in ruby?

$even_parity = '\0\201\202\3\204\5\6\207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\
245\246\47\50\251\252\53\254\55\56\2570\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\3
27\330YZ\333\134\335\336_\140\341\342c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377\0\201\202\3\204\5\6\207\
210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\245\246\47\50\251\252\53\254\55\56\2570\2
61\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ\333\134\335\336_\140\341\342c\34
4ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377';

eval <<EDQ;

sub setEvenParity {
   my(\@s) = \@_;
   foreach (\@s) {
       tr/\\0-\\377/$even_parity/;
   }
   wantarray ? \@s : join '', \@s;
}

EDQ
die $@ if $@;

$out = setEvenParity('s');
print $out;

@even_parity = '\0\201\202\3\204\5\6\207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\
245\246\47\50\251\252\53\254\55\56\2570\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\3
27\330YZ\333\134\335\336_\140\341\342c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377\0\201\202\3\204\5\6\207\
210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\245\246\47\50\251\252\53\254\55\56\2570\2
61\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ\333\134\335\336_\140\341\342c\34
4ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377';

eval <<EDQ

def setEvenParity(str)
str.tr("\\0-\\377",@even_parity)
end

EDQ

out = setEvenParity('s')
print out

Have you tried the seemingly simple approach like this, which avoids eval:

ratdog:~ mike$ irb --prompt simple
>> @upper_case = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
>> def uc(s)
>> s.tr('abcdefghijklmnopqrstuvwxyz', @upper_case)
>> end
=> nil
>> uc('banana')
=> "BANANA"
>> @upper_case = 'abcdefghijklmnopqrstuvwxyz'
=> "abcdefghijklmnopqrstuvwxyz"
>> uc('banana')
=> "banana"

Maybe I am misunderstanding what you want to do...

Hope this helps,

Mike

···

On 12-Aug-06, at 10:32 PM, snacktime wrote:

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

Have you tried the seemingly simple approach like this, which avoids
eval:

ratdog:~ mike$ irb --prompt simple
>> @upper_case = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
>> def uc(s)
>> s.tr('abcdefghijklmnopqrstuvwxyz', @upper_case)
>> end
=> nil
>> uc('banana')
=> "BANANA"
>> @upper_case = 'abcdefghijklmnopqrstuvwxyz'
=> "abcdefghijklmnopqrstuvwxyz"
>> uc('banana')
=> "banana"

Yes I tried it without eval also, but it won't produce the same output
as the perl code. I've tried every incantation I can think of but no
luck. I'm checking my results by comparing them to the output of
perl's String::Parity. The perl code I posted is basically an
abbreviation of what String::Parity does when setting even parity.
It's the last bit in this damn module I'm working on also:) If I get
this figured out I'll be done.

Here is a shortened version. the ruby and perl code do not produce
the same output. I want the ruby version to produce the same output
as the perl version.

In perl:

$str = "s";
$str =~ tr/\0-\377/\0\201\202\3\204\5\6\207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243
\44\245\246\47\50\251\252\53\254\55\56\2570\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324
UV\327\330YZ\333\134\335\336_\140\341\342c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377\0\201\202\3\204\5\6\
207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\245\246\47\50\251\252\53\254\55\56\25
70\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ\333\134\335\336_\140\341\342
c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377/;

In ruby:

's'.tr!("\0-\377","\0\201\202\3\204\5\6\207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243
\44\245\246\47\50\251\252\53\254\55\56\2570\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324
UV\327\330YZ\333\134\335\336_\140\341\342c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377\0\201\202\3\204\5\6\
207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\245\246\47\50\251\252\53\254\55\56\25
70\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ\333\134\335\336_\140\341\342
c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377")

Have you tried the seemingly simple approach like this, which avoids
eval:

ratdog:~ mike$ irb --prompt simple
>> @upper_case = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
=> "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
>> def uc(s)
>> s.tr('abcdefghijklmnopqrstuvwxyz', @upper_case)
>> end
=> nil
>> uc('banana')
=> "BANANA"
>> @upper_case = 'abcdefghijklmnopqrstuvwxyz'
=> "abcdefghijklmnopqrstuvwxyz"
>> uc('banana')
=> "banana"

Yes I tried it without eval also, but it won't produce the same output
as the perl code. I've tried every incantation I can think of but no
luck. I'm checking my results by comparing them to the output of
perl's String::Parity. The perl code I posted is basically an
abbreviation of what String::Parity does when setting even parity.
It's the last bit in this damn module I'm working on also:) If I get
this figured out I'll be done.

Can you give me a hint as to what doesn't work? For a simple upper case subset of your code (using double quotes) I see

ratdog:~ mike$ irb --prompt simple
>> @even_parity = "AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ"
=> "AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ"
>> @even_parity.length
=> 26
>> def setEvenParity(s)
>> s.tr('A-Z', @even_parity)
>> end
=> nil
>> setEvenParity('ABACAB')
=> "ABA\303AB"

seems pretty reasonable - can you show a simple example of what doesn't behave as you want?

Hmm, thinking about it, when you do the Ruby eval, are uou missing quotes around @even_parity?

Mike

···

On 12-Aug-06, at 11:19 PM, snacktime wrote:

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

Can you give me a hint as to what doesn't work? For a simple upper
case subset of your code (using double quotes) I see

I'm implementing string parity functions using perl's String::Parity
as the base to work from. I'm assuming that the ruby code is working
as it was designed to, but I want to find out what I need to do to
make it work like the perl example. I just posted a shorter, easier
to test version. The perl version outputs a string correctly set to
even parity. The ruby code doesn't. I've tried quotes, no quotes,
double quotes, eval, beating my head in the wall, all of that. It's
something else I am missing.

Chris

I think it's due to multiple interpolations - first in double quotish context and then as a pattern for tr, where \ and - are the only real metacharacters.

Looks like you need to do something like use \\\55 in place of \55 (a - character) and \\\134 in place of \134 (a \ character)

Ick.

Program and output below

#!/usr/bin/env ruby

str = "()*+,-./09AZ[_]abcpqrstuvwxyz\376"
p str
str.tr!("\0-\377","\0\201\202\3\204\5\6\207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\245\246\47\50\251\252\53\254\\\55\56\2570\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ\333\\\134\335\336_\140\341\342c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377\0\201\202\3\204\5\6\207\210\11\12\213\14\215\216\17\220\21\22\223\24\225\226\27\30\231\232\33\234\35\36\237\240\41\42\243\44\245\246\47\50\251\252\53\254\\\55\56\2570\261\2623\26456\267\2709\72\273\74\275\276\77\300AB\303D\305\306GH\311\312K\314MN\317P\321\322S\324UV\327\330YZ\333\\\134\335\336_\140\341\342c\344ef\347\350ij\353l\355\356o\360qr\363t\365\366wx\371\372\173\374\175\176\377")
p str

output:

"()*+,-./09AZ[_]abcpqrstuvwxyz\376"
"(\251\252+\254-.\25709AZ\333_\335\341\342c\360qr\363t\365\366wx\371\372~"

Hope this helps,

Mike

···

On 12-Aug-06, at 11:44 PM, snacktime wrote:

Can you give me a hint as to what doesn't work? For a simple upper
case subset of your code (using double quotes) I see

I'm implementing string parity functions using perl's String::Parity
as the base to work from. I'm assuming that the ruby code is working
as it was designed to, but I want to find out what I need to do to
make it work like the perl example. I just posted a shorter, easier
to test version. The perl version outputs a string correctly set to
even parity. The ruby code doesn't. I've tried quotes, no quotes,
double quotes, eval, beating my head in the wall, all of that. It's
something else I am missing.

Chris

--

Mike Stok <mike@stok.ca>
http://www.stok.ca/~mike/

The "`Stok' disclaimers" apply.

I figured out the problem. Ruby tr doesn't handle octal numbers like
perl does. Not sure if it's just not implemented or maybe there is a
correct way to do it I'm not sure of. In any case instead of trying
to use tr to map the octal numbers I just made an array of decimal
numbers for the even bit map and then made this function. Works fine.

def setEvenParity(str)
  new = []
  str.each_byte {|b| new << @even_parity[b]}
  new.pack("C*")
end