Шаг 1
cipher.rb:4:in `block in vigenere_cipher': private method `shift!' called for "c":String (NoMethodError)
shift!
не определен в классе струнных, но на самом высоком уровне. Так заменить c=c.shift!(c,keyIndex)
на c=shift!(c,keyIndex)
Шаг 2
cipher.rb:17:in `[]': no implicit conversion of String into Integer (TypeError)
Линия 16 определяет:
finalLetterIndex=alphabet[inititalLetterIndex+keyIndex]
алфавит содержит буквы как строки, так finalLetterIndex
не является индексом (Числовой), а строка ,
В строке 17 вы пытаетесь использовать эту строку в качестве индекса.
Заменить строку 16 с:
finalLetterIndex=inititalLetterIndex+keyIndex
Шаг 3
Ваш сценарий не вызывает каких-либо исключений больше. Он также ничего не отображается, так что добавить путы к последней строке:
puts vigenere_cipher("cat", [1,2,3]).inspect
возвращает:
[0, 0, 0]
Шаг 4
keyIndex
, кажется, застрял в 0. Почему? Посмотрите на линии 6:
if keyIndex=key_sequence.length
Он не проверяет равенство, он присваивает keyIndex
к key_sequence.length
. Поскольку любое число является правдивым в Ruby, оно выполняет код внутри оператора if. Заменить
if keyIndex==key_sequence.length
Шаг 5
Ваш код возвращает [nil, nil, 0]
. Зачем?
string
определяется как результат map
. map
возвращает массив, в котором каждый элемент является результатом последней выполненной команды внутри блока: в этом случае оператор if
.
if
возвращает nil
, когда условие не выполняется, и возвращает последнюю выполненную команду в противном случае. В этом случае 0
.
Добавить c
в последней строке вашего map
блока.
Шаг 6
Ваш код теперь возвращает ["c", "b", "v"]
. Зачем?
Вы перемещаете только по shiftIndex
, не на сумму, указанную в key_sequence
Array. Заменить
c=shift!(c,keyIndex)
с
c=shift!(c,key_sequence[keyIndex])
Шаг 7
Ваш код возвращает ["d", "c", "w"]
. Почти готово!
Ruby - динамичный язык. Вы можете перезаписать String string
с помощью Array, но это смутит других и ваше будущее.
Использование array
или letters
вместо string
и вернуть letters.join
Ваш скрипт теперь возвращает "dcw"
.
Он должен выглядеть следующим образом:
def vigenere_cipher(string, key_sequence)
keyIndex=0
letters=string.each_char.map do |c|
c=shift!(c,key_sequence[keyIndex])
keyIndex+=1
if keyIndex==key_sequence.length
keyIndex=0
end
c
end
return letters.join
end
def shift!(c,keyIndex)
alphabet = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
inititalLetterIndex=alphabet.index(c)
finalLetterIndex=inititalLetterIndex+keyIndex
return alphabet[finalLetterIndex]
end
Шаг 8
vigenere_cipher("Hello", [1,2,3])
поднимает
cipher.rb:17:in 'shift!': undefined method '+' for nil:NilClass (NoMethodError)
.
Ну, «H» не встречается в вашем алфавите. Использование downcase:
array=string.downcase.each_char.map do |c|
Шаг 9
vigenere_cipher("Hello World", [1,2,3])
не работает, либо из-за пространства. Удалить все, что не письмо:
array=string.downcase.delete('^a-z').each_char.map do |c|
Шаг 10
vigenere_cipher("zzz", [1,2,3])
возвращает пустую строку, потому что нет никакого письма после z
.
Использование по модулю 26:
return alphabet[finalLetterIndex%26]
Шаг 11
Удалить опечаток, не используйте CamelCase для переменных, удалить ненужные return
и вы получите:
def vigenere_cipher(string, key_sequence)
key_index = 0
letters = string.downcase.delete('^a-z').each_char.map do |c|
c = shift(c, key_sequence[key_index])
key_index = (key_index + 1) % key_sequence.length
c
end
letters.join
end
def shift(c, key_index)
alphabet = ('a'..'z').to_a
initial_letter_index = alphabet.index(c)
final_letter_index = initial_letter_index + key_index
alphabet[final_letter_index % 26]
end
Шаг 12
Использование each_char
, zip
a й cycle
, я бы переписать весь код так:
class Integer
# 0 => 'a', 1 => 'b', ..., 25 => 'z', 26 => 'a'
def to_letter
('a'.ord + self % 26).chr
end
end
class String
# 'A' => '0', 'a' => 0, ..., 'z' => 25
def to_code
self.downcase.ord - 'a'.ord
end
end
def vigenere_cipher(string, key)
short_string = string.delete('^A-Za-z')
short_string.each_char.zip(key.cycle).map do |char, shift|
(char.to_code + shift).to_letter
end.join
end
Шаг 13
Википедия article использует строку как ключ:
def vigenere_cipher(string, key)
short_string = string.delete('^A-Za-z')
short_string.each_char.zip(key.each_char.cycle).map do |char, shift|
(char.to_code + shift.to_code).to_letter
end.join
end
vigenere_cipher('Attack at dawn!', 'LEMON').upcase # => "LXFOPVEFRNHR"
Шаг 14
Вы должны также иметь возможность расшифровать сообщение:
Ну, это было дольше, чем ожидалось! : D
'c' - это строка (один символ). Нет метода 'String # shift!'. –
Попробуйте '' cat'.chars.zip ([1,2,3]). Map {| c, i | (c.ord + i) .chr} .join # => "dcw" '. –
но я определяю смену! метод ... извините, я новичок в этом. Почему мой определенный сдвиг! метод не работает? –