我在theOdinProject学习Ruby,我需要构建Caeser Cipher。这是我的代码:
def caesar_cipher plaintext, factor
codepoints_array = []
ciphertext = ""
plaintext.split('').each do |letter|
if letter =~ /[^a-zA-Z]/
codepoints_array << letter.bytes.join('').to_i
else
codepoints_array << letter.bytes.join('').to_i + factor
end
end
ciphertext = codepoints_array.pack 'C*'
puts ciphertext
end
caesar_cipher("What a string!", 5)
我打赌它不是真的&#34;优雅&#34;但这里的主要问题是输出应该是&#34; Bmfy f xywnsl!&#34;但我有什么&#34; \ mfy f xywnsl!&#34;。我现在已经在这项任务中苦苦挣扎了几天,但我仍然不知道如何&#34;链接&#34;字母表这样&#39; z&#39;成为&#39; a&#39;因子== 1。
我可以在OdinProject上检查其他人的完成任务,但他们的代码通常不同/更专业,我试图得到一个提示,而不是最终的解决方案。如果有人能暗示我如何解决这个问题,我会非常感激。提前谢谢。
答案 0 :(得分:1)
如果ASCII table只有26个字符,那么您的代码几乎可以正常工作。
但W
不是w
,z
后来的是{
,而不是a
。
因此,您首先需要将downcase应用于您的字母,偏移字节码以使a
为0,并执行每次计算modulo 26。
def caesar_cipher plaintext, factor
codepoints_array = []
ciphertext = ""
a_codepoint = 'a'.ord
plaintext.split('').each do |letter|
if letter =~ /[^a-zA-Z]/
codepoints_array << letter.bytes.join('').to_i
else
shifted_codepoint = letter.downcase.bytes.join('').to_i + factor
codepoints_array << (shifted_codepoint - a_codepoint) % 26 + a_codepoint
end
end
ciphertext = codepoints_array.pack 'C*'
ciphertext
end
puts caesar_cipher("What a string!", 5) #=> "bmfy f xywnsl!"
我刚才为Vigenere chiper写了一个小的Ruby脚本。凯撒密码只是它的变种,每个角色都有相同的因素:
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 caesar_cipher(string, factor)
short_string = string.delete('^A-Za-z')
short_string.each_char.map do |char|
(char.to_code + factor).to_letter
end.join
end
puts caesar_cipher("What a string!", 5) #=> "bmfyfxywnsl"
puts caesar_cipher("bmfyfxywnsl", -5) #=> "whatastring"
使用密码,建议删除任何标点符号或空格,因为它们可以更容易地使用统计分析对字符串进行解码。
无论如何,凯撒密码非常弱。