На ваш вопрос ответили, но я бы хотел предложить более похожий на Ruby способ решения вашей проблемы.
Если вы посмотрите на документ для Hash # gsub , вы увидите, что вторая форма метода, написанная str.gsub(pattern, hash)
, где pattern
обычно является регулярным выражением, а hash
- это: конечно, хеш Вот пример.
h = { 'c'=>'C', 'a'=>'A', 'n'=>'N', 'd'=>'D', 'o'=>'$', 'g'=>'G' }
'cat and dog.'.gsub(/./, h)
#=> "CAANDD$G"
/./
- это регулярное выражение, которое просто соответствует любому одному символу в str
. Сначала он соответствует 'c'
, затем 'a'
и так далее. Рассмотрим первую букву 'c'
. Ruby проверяет, есть ли у хэша h
ключ 'c'
. Это так, что символ заменяется значением 'c'
в хэше, 'C'
. Далее 'a'
заменяется на 'A'
. Однако h
не имеет ключа 't'
, поэтому Ruby преобразует 't'
в пустую строку. Точно так же символы ' '
(пробел) и '.'
(точка) не являются ключами в h
, поэтому эти символы также преобразуются в пустые строки.
Эта форма gsub
кажется идеальной для шифрования и дешифрования строк.
Давайте сначала создадим хеш-кодировку.
arr = ('a'..'z').zip('01'..'26')
#=> [["a", "01"], ["b", "02"],..., ["z", "26"]]
encode = arr.to_h
#=> {"a"=>"01", "b"=>"02",..., "z"=>"26"}
encode[' '] = "27"
encode['.'] = "28"
Так что теперь
encode
#=> {"a"=>"01", "b"=>"02",..., "z"=>"26", " "=>"27", "."=>"." }
'a'..'z'
и '01'..'2'
равны Диапазон с. См. Документы для Enumerable # zip и Array # to_h . Обычно мы записываем эти две строки как одно цепочечное выражение.
encode = ('a'..'z').zip('01'..'26').to_h
Обратите внимание, что значения начинаются с "01"
, так что все строки одинаковой длины (2). Если мы начали значения с "1"
, как мы могли бы декодировать строку "1226"
? Будет ли это 'abbd'
(1-2-3-4), 'abz'
(1-2-26), 'lz'
(12-26) или одна из других возможностей. Это не проблема, если все значения хеша encode
являются строками длины 2.
Мы могли бы создать хеш для декодирования таким же образом ({'01'=>'a', '02'=>'b',...}
), но проще использовать метод Hash # invert :
decode = encode.invert
#=> {"01"=>"a", "02"=>"b",..., "26"=>"z", "27"=>" ", "28"=>"."}
Если строка для шифрования
str = "how now, brown cow."
мы можем закодировать его с помощью
encrypted = str.gsub(/./, encode)
#=> "081523271415232702181523142703152328"
, который затем может быть декодирован с помощью
decoded = encrypted.gsub(/../, decode)
#=> "how now, brown cow."
Обратите внимание, что регулярное выражение ("regex") для декодирования совпадает с любыми двумя символами одновременно.
Два очка. Во-первых, мы могли бы использовать Hash # update (он же merge!
) для записи
encode = ('a'..'z').zip('01'..'26').to_h
encode.update( ' '=>"27", '.'=>"28" )
Ruby позволяет писать encode.update({ ' '=>"27", '.'=>"28" })
без фигурных скобок (пример синтаксический сахар ).
Лучше использовать Hash # default_proc = для записи
encode = ('a'..'z').zip('01'..'26').to_h
encode.default_proc = proc { |h,k| h[k] = k }
Это немного сложно для новичка из Ruby, но в результате encode[k]
возвращает k
, если encode
не имеет ключа k
. Например, encode['.'] #=> '.'
.