2

我做了一个简单的ROT13程序,但我不明白一件事:

a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
(a.length+1).times do |i|
  print  a[i + 13]
  if i>13
    print a[i %14]
  end

end

输出:

NOPQRSTUVWXYZABCDEFGHIJKLM

如果我不添加+1after a.length,则迭代以 letter 结束L。但是,如果我print a[i]在迭代中使用,它通常以不需要添加的方式开始A和结束。Z+1

有人可以为我解释这个谜吗?

4

3 回答 3

4

我只需要一个快速的 rot13 one liner,这个 SO 条目是第一个谷歌结果。我继续搜索并找到了一个由@xfaider 提供的超小号,它对我的​​目的来说足够好用。

只是要把它贴在这里给下一个想要单线的人。

string.tr("A-Za-z", "N-ZA-Mn-za-m")

于 2018-11-13T15:57:35.550 回答
3

您可能知道,.times循环调用块指定的次数,向每次迭代传递一个递增的值。

如果我们说26.times {|i| puts i}它将打印从 0 到 25 的值。最多,但不包括最后一个值。

现在让我们来看看循环。在第一次迭代时,i是 0。所以我们打印字符串的第 14 个字符"N"(在索引 13,从零开始)。我们不进入条件,因为 0 不大于 13。在第二次迭代中,我们打印第 15 个字符,"O"。并继续这样做,直到我们到达i=14.

至此,“魔法”开始了。首先,我们尝试打印字符串的第 27 个字符。没有这样的字符,所以我们实际上什么也没有打印。然后条件被触发,我们进入。

i % 14等于 0,所以我们打印第零个字符"A". 下一次迭代,我们在索引 1 ( ) 处打印字符,15 % 14依此类推,直到.times完成迭代并停止调用该块。现在,要使这个逻辑起作用, for 的最后一个值i 必须是 26,这样我们就可以得到 12i % 14和 print "M"

整个字符串的长度是 26。记住,.times最多计数但不包括数字?这就是为什么我们将长度加一,使其从 0 计数到 26。这就是奥秘。

改进此代码的方法有很多,您将及时了解它们。:)

更新

知道代码看起来有些奇怪。当然,还有一个错误。什么时候是 13 i我们第一次不打印,也不进入条件。我们浪费了一次迭代。这是“off by 1”类错误的经典示例。这是不浪费迭代且不包含任何秘密的代码的固定版本:

a.length.times do |i|
  print  a[i + 13]
  if i > 12
    print a[i % 13]
  end
end
于 2016-11-17T18:38:29.073 回答
1

字母串的长度是 26,但是索引是从 0 开始的。在这种情况下,字母 Z 是索引号 25。times 方法将不会运行最终迭代 (26)。因此,为了解决这个问题,我们在长度上加了一个 +1。

于 2016-11-17T20:48:05.780 回答