问题
There is something mysterious to me about the escape status of a backslash within a single quoted string literal as argument of String#tr
. Can you explain the contrast between the three examples below? I particularly do not understand the second one. To avoid complication, I am using 'd'
here, which does not change the meaning when escaped in double quotation ("\d"
= "d"
).
'\\'.tr('\\', 'x') #=> "x"
'\\'.tr('\\d', 'x') #=> "\\"
'\\'.tr('\\\d', 'x') #=> "x"
回答1:
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.
来源:https://stackoverflow.com/questions/5926457/escape-status-within-a-string-literal-as-argument-of-stringtr