2016-12-15 4 views
1

Я пытался решить следующую проблему и столкнулся с ошибкой. Суть проблемы состоит в том, чтобы использовать заданную последовательность клавиш для шифрования строки. Например, при задании «cat» и [1,2,3] результат должен быть «dcw» Любые предложения? ошибка была следующаячастный метод, называемый noMethodError ruby ​​

def vigenere_cipher(string, key_sequence) 
    keyIndex=0 
    string=string.each_char.map do |c| 
    c=c.shift!(c,keyIndex) 
    keyIndex+=1 
    if keyIndex=key_sequence.length 
     keyIndex=0 
    end 
    end 
    return string 
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=alphabet[inititalLetterIndex+keyIndex] 
    return alphabet[finalLetterIndex] 
end 

vigenere_cipher("cat", [1,2,3]) 
# private method `shift!' called for "c":String (NoMethodError) 
+0

'c' - это строка (один символ). Нет метода 'String # shift!'. –

+0

Попробуйте '' cat'.chars.zip ([1,2,3]). Map {| c, i | (c.ord + i) .chr} .join # => "dcw" '. –

+0

но я определяю смену! метод ... извините, я новичок в этом. Почему мой определенный сдвиг! метод не работает? –

ответ

3

Вы пытаетесь вызвать shift! на строковом объекте, который не определяет на String класса, вместо того, чтобы вы определили на главном объекте. Вы можете назвать это как shift!(c,keyIndex) вместо c.shift!(c,keyIndex)

1

Если вы хотите, чтобы позвонить вам метод shift! на строку, вы должны определить его на String класса.

class String 
    def shift!(keyIndex) 
    # you can access `c` using `self` here 
    ... 
    end 
end 

Тогда вы можете назвать его как c.shift!(keyIndex) (Примечание аргументы различны).

1

Шаг 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

+0

Что касается шага 10, где говорится, что' z 'со смещением 1 Я бы сказал, что 'vigenere_cipher (" zzz ", [1,2,3])' недопустимо, что 'vigenere_cipher (" zzz ", [-25, -24, -, 23]) # > 'abc''is необходимо для создания нужного отображения. –

+0

@CarySwoveland: По историческим причинам. См. статью в Википедии: https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher. Этот шифр был определен задолго до ASCII-таблицы. Каждая операция выполняется по модулю 26. –

+0

Не зная о «Vigenere», я предположил, что имя метода было изобретением OP. Естественно, я подозревал, что шифр был целью OP, но я шел o n буквальное толкование вопроса. –

Смежные вопросы