我通过The Odin Project学习Ruby。我的任务是建立一个Caesar Cipher程序,而且我整天都在反对这个问题。我终于写了我认为是一个有效的程序,但我不理解输出。这是Git:https://github.com/PAMulligan/caesar_cipher.git。如果有人对我出错的地方有任何了解,我会很乐意帮助。
答案 0 :(得分:5)
让我为你毁了它......
你的基本逻辑似乎既健全又过于复杂。
以下是一些意见:
c.ord + cypher
可能会给你一个不是UTF8有效的意外值。另外,在'д'.ord == 1076
期间,您应该知道1076.chr
会引发RangeError
例外。.ord
和.chr
),我们应该考虑到字节限制为8位(或一个八位字节)的事实 - 因此加密的最高数字byte是255。凯撒算法:
将字符串转换为数字数组,每个数字代表一个字母......哦等等,有一个内置方法可以做到这一点。String#bytes
返回一个整数数组,表示每个字节的值在二进制字符串中。
通过添加密码来迭代数组以更改数组(使用Array#map!
来就地更改数组)。在这里我们只需要记住字节的上限值为255,因此我们应该使用'modulu'方法Fixnum#%
。
现在我们只需要将字节数组(使用新值)转换回字符串...现在我们知道String有一个方法将字符串转换为字节数组,所以它反逻辑也是合乎逻辑的 - 我会采用Array#pack
方法。
以下是草图的要点:
some_string.bytes.map! {|i| (i +/- cypher) % 255 } .pack 'C*'
# the +/- refers to the question of encoding vs. decoding and won't work.
你真正需要的只是一行。
我建议你假设你使用的语言几乎有你需要的任何方法。因此,如果你需要执行一个动作 - 例如获取一个unicode字符串并将其转换为数字数组(相对于我引入的限制,这是一个二进制八位字节限制为255) - Ruby已经覆盖了你。
现在,由于我的回答可能在某种程度上破坏了挑战 - 让我为你提供挑战。
重写我提供的解决方案,使其适用于UTF8字符串(标准编码),允许您加密更强,因为密码的限制将是更高的UTF8编码限制,而不是一个字节的255限制。
修改强>
由于“一行”概念使答案看起来比它更高级,如果它是多行的,那么这就是代码的样子:
# the encryption method takes a string and a number
def caesar_encrypt string, cypher
# string.bytes will return an array of numbers.
# The numbers are between 0 and 255 (8 bits or 1 byte)
# https://en.wikipedia.org/wiki/Byte
array = string.bytes
# using the Array.map! changes the array in place.
# it's the same as: array = array.map {...}
# the format: { ... } is a one line block, similar to the do ... end.
array.map! do |i|
(i + cypher) % 255
end
# array.pack is used for taking objects in an array and transforming them
# to a string. the 'C*' means we are packing bytes together to a string.
# There are more options such as 'N*' which would pack 32 bit numbers into
# a string. It's a great way to save or manipulate binary data,
# which is at the core of all digital data.
array.pack 'C*'
end
def caesar_decrypt
caesar_encrypt string, (0-cypher)
end
请注意,Array#pack
可能有点高级,使用原始解决方案也可以...现在我们使用字节,Fixnum#chr
应该按预期工作。
def caesar_encrypt string, cypher
array = string.bytes
array.map! do |i|
(i + cypher) % 255
end
out = ""
array.each {|c| out << c.chr}
out
end
答案 1 :(得分:2)
这是我可以帮助的。现在有三条线让你感到悲伤。
第一个问题是第33行if i == (65..90)
现在,该行询问我是否等于65到90之间的整数范围,这当然不是。此行返回
false
,您的if
分支甚至从未执行过。这就是为什么你要回到你开始时的相同信件!您正在寻找的是Ruby的
between?(a,b)
方法,其中a
是范围的底部,b
是顶部。因此,将该行更改为:
if i.between?(65, 90)
你很高兴。
让您感到悲痛的第二行是第39行elsif i == (97..122)
此行是一个问题,原因与第一行完全相同。以同样的方式修复它。
让您感到悲伤的第三行是第14行puts convert_to_char(cipher_array)
。
你的
来使用此功能convert_to_char
方法正在返回一个数组,当Ruby被要求puts
一个数组时,它只会在自己的行上弹出每个项目。使用Ruby的join
方法,它将所有元素连接成一个字符串。您可以通过将第14行更改为:
puts convert_to_char(cipher_array).join
注意,您也可以将
join
添加到第58行,并获得相同的结果。试试看吧!
我希望这可以帮助你,并继续学习!
答案 2 :(得分:0)
我使用了Dan Phillips给出的建议,即改变我的&#34;如果i == ...&#34;陈述到&#34;如果i.between?&#34;陈述,它完美地运作了!