It seems like I’ve seen quite a few programming puzzles in the last few weeks that involved translating mistyped input in which the hands were shifted (right) on the keyboard. My first thought was the tr
utility in *nix operating systems, but didn’t immediately go looking for or notice that ruby has a tr method on string. However, after doing a trivial implementation involving keyboard rows like the following, I stumbled on the tr
method.
# initial array of characters/strings to shift back to the left with [index-1]
KEYBOARD_ROWS= [
'`1234567890-=',
'qwertyuiop[]\\', # need to escape the backslash or else debugging pain
"asdfghjkl;'", # double-quotes here because single quote embedded
'zxcvbnm,./',
'~!@#\$%^&*()_+',
'QWERTYUIOP{}|',
'ASDFGHJKL:"',
'ZXCVBNM<>?'
].join
Attempting to rewrite this for .tr
presented a few challenges, however. If you are substituting for \
, -
, or ~
, you have to escape the characters. You also have to escape them from their string representation, which makes for some head-spinning levels of escaping (zsh
users who run shell commands through kubectl
might be familiar with this pain as well):
# puts '\\~-'.tr('\\', 'a') # doesn't match because \ is passed to tr and not escaped
a~-
# puts '\\~-'.tr('\\\\', 'a') # now \\ is passed to tr, which is
a~-
# puts '\\~-'.tr("\\\\\\", 'a') # with double quotes, you need an extra pair, for 6 total.
a~-
# puts '\\~-'.tr('\\~', 'b') # the escaping backslash needs to be doubled
\b-
# puts '\\~-'.tr("\\\~", 'b') # the escaping backslash needs to be tripled
\b-
# puts '\\~-'.tr('\\-', 'c') # the escaping backslash needs to be doubled
\~c
# puts '\\~-'.tr("\\\-", 'c') # the escaping backslash needs to be tripled
\~c
So if you’re going to use translate to “shift” hands back to the left, the two arguments to tr
, SHIFTED_KEYBOARD_ROWS
and UNSHIFTED_KEYBOARD_ROWS
would have to be defined with the following escaping:
SHIFTED_KEYBOARD_ROWS =
[
'1234567890\\-=',
'wertyuiop[]\\\\', # 4x backslash = backslash
"sdfghjkl;'",
'xcvbnm,./',
'!@#\$%\^&*()_+',
'WERTYUIOP{}|',
'SDFGHJKL:"',
'XCVBNM<>?'
].join
UNSHIFTED_KEYBOARD_ROWS= [
'`1234567890\-',
'qwertyuiop[]', # need to escape the backslash or else debugging pain
'asdfghjkl;',
'zxcvbnm,.',
'~!@#\$%\^&*()_',
'QWERTYUIOP{}',
'ASDFGHJKL:',
'ZXCVBNM<>?'
].join
def self.translate(string)
string.tr(SHIFTED_KEYBOARD_ROWS, UNSHIFTED_KEYBOARD_ROWS)
end