Escaping in tr
The first argument of tr
works much like bracket character grouping in regular expressions. You can use ^
in the start of the expression to negate the matching (replace anything that doesn't match) and use e.g. a-f
to match a range of characters. Since it has control characters, it also does escaping internally, so you can use -
and ^
as literal characters.
print 'abcdef'.tr('b-e', 'x') # axxxxf
print 'abcdef'.tr('b\-e', 'x') # axcdxf
Escaping in Ruby single quote strings
Furthermore, when using single quotes, Ruby tries to include the backslash when possible, i.e. when it's not used to actually escape another backslash or a single quote.
# Single quotes
print '\\' # \
print '\d' # \d
print '\\d' # \d
print '\\\d' # \\d
# Double quotes
print "\\" # \
print "\d" # d
print "\\d" # \d
print "\\\d" # \d
The examples revisited
With all that in mind, let's look at the examples again.
'\\'.tr('\\', 'x') #=> "x"
The string defined as '\\'
becomes the literal string \
because the first backslash escapes the second. No surprises there.
'\\'.tr('\\d', 'x') #=> "\\"
The string defined as '\\d'
becomes the literal string \d
. The tr
engine, in turn uses the backslash in the literal string to escape the d
. Result: tr
replaces instances of d
with x.
'\\'.tr('\\\d', 'x') #=> "x"
The string defined as '\\\d'
becomes the literal \\d
. First \\
becomes \
. Then \d
becomes \d
, i.e. the backslash is preserved. (This particular behavior is different from double strings, where the backslash would be eaten alive, leaving only a lonesome d
)
The literal string \\d
then makes tr
replace all characters that are either a backslash or a d
with the replacement string.
'\\rs'.tr('\\rs','x')
return\\xx
?! I would have expected a return value ofxxx
. And in the documentation example"hello".tr('aeiou', '*')
,*
is shorter thanaeiou
, so what does If to_str is shorter than from_str, it is padded with its last character mean? Is it a bug? Is it a fly? Is it Superman? :D – Orpington"hello".tr('aeiou', '*#')
is the same as"hello".tr('aeiou', '*####')
. :D – Huckaback'\\d'.tr('\\d','xx)
? I don't expect what it does give.. – Orpingtonxx
too, but the actual result is\x
(at least on 1.8.7). – Orpingtontr
's behaviour, as well as listing the three examples above, I would have seen how it handled normal characters when there's differences in string length. – Rambutan