对学生项目中的输出感到困惑

时间:2015-09-16 01:57:10

标签: ruby

我通过The Odin Project学习Ruby。我的任务是建立一个Caesar Cipher程序,而且我整天都在反对这个问题。我终于写了我认为是一个有效的程序,但我不理解输出。这是Git:https://github.com/PAMulligan/caesar_cipher.git。如果有人对我出错的地方有任何了解,我会很乐意帮助。

3 个答案:

答案 0 :(得分:5)

让我为你毁了它......

你的基本逻辑似乎既健全又过于复杂。

以下是一些意见:

  1. 您为已存在的任务定义了许多方法。始终假设Ruby已经涵盖了您所需的任何任务 - 即使您错了,搜索文档也会让您不同的选择开启您的想法。
  2. 您忽略了String是UTF8编码的事实。所以c.ord + cypher可能会给你一个不是UTF8有效的意外值。另外,在'д'.ord == 1076期间,您应该知道1076.chr会引发RangeError例外。
  3. 假设您期望ASCII值(使用.ord.chr),我们应该考虑到字节限制为8位(或一个八位字节)的事实 - 因此加密的最高数字byte是255。
  4. 最好使用模块将方法限制在命名空间 - 我将在这里做,因为我不知道你在学习的时间点。
  5. 凯撒算法:

    1. 将字符串转换为数字数组,每个数字代表一个字母......哦等等,有一个内置方法可以做到这一点。String#bytes返回一个整数数组,表示每个字节的值在二进制字符串中。

    2. 通过添加密码来迭代数组以更改数组(使用Array#map!来就地更改数组)。在这里我们只需要记住字节的上限值为255,因此我们应该使用'modulu'方法Fixnum#%

    3. 现在我们只需要将字节数组(使用新值)转换回字符串...现在我们知道String有一个方法将字符串转换为字节数组,所以它反逻辑也是合乎逻辑的 - 我会采用Array#pack方法。

    4. 以下是草图的要点:

       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;陈述,它完美地运作了!