步驟1
cipher.rb:4:in `block in vigenere_cipher': private method `shift!' called for "c":String (NoMethodError)
shift!
未在String類定義的,但在頂層。 因此,通過c=shift!(c,keyIndex)
步驟2
cipher.rb:17:in `[]': no implicit conversion of String into Integer (TypeError)
線16限定替換c=c.shift!(c,keyIndex)
:
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
語句。當條件不滿足時返回,否則返回最後執行的命令。在這種情況下,0
。
在map
塊的最後一行添加c
。
步驟6
現在您的代碼返回["c", "b", "v"]
。爲什麼?
您只能移動shiftIndex
,而不是key_sequence
Array中定義的數量。更換
c=shift!(c,keyIndex)
與
c=shift!(c,key_sequence[keyIndex])
步驟7
你的代碼返回["d", "c", "w"]
。差不多了!
Ruby是一種動態語言。你可以用Array來自由地覆蓋字符串string
,但它會混淆他人和你未來的自我。
使用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
刪除錯別字,不要使用變量駝峯,消除不必要的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
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使用String作爲重點:第二cycle
,我想這種方式重寫整個代碼
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
你也應該能夠解密該消息:
def vigenere_cipher(string, key, decrypt = false)
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 * (decrypt ? -1 : 1)).to_letter
end.join
end
vigenere_cipher("LXFOPVEFRNHR", 'LEMON', :decrypt) #=> "attackatdawn"
好吧,那比預期的要長! :D
'c'是一個字符串(單個字符)。沒有方法'String#shift!'。 –
嘗試''cat'.chars.zip([1,2,3])。map {| c,i | (c.ord + i).chr} .join#=>「dcw」'。 –
但我定義了這個轉變!方法...抱歉,我是新手。爲什麼我定義的班次!方法不起作用? –