Easy ROT13 Ruby "programme" 谜底
Easy ROT13 Ruby "programme" mystery
我做了一个简单的ROT13程序,有一点不明白:
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
(a.length+1).times do |i|
print a[i + 13]
if i>13
print a[i %14]
end
end
输出:
NOPQRSTUVWXYZABCDEFGHIJKLM
如果我不在 a.length
之后添加 +1
,则迭代以字母 L
结束。但是,如果我在迭代中使用 print a[i]
,它通常以 A
开始并以 Z
结束,不需要添加 +1
。
有人可以为我解释这个谜吗?
如您所知,.times
循环调用块指定次数,并在每次迭代中传递一个增量值。
如果我们说 26.times {|i| puts i}
它将打印从 0 到 25 的值。最多但不包括最后一个值。
现在让我们来看看这个循环。在第一次迭代中,i
为 0。因此我们打印字符串的第 14 个字符,"N"
(在索引 13 处,从零开始)。我们不进入条件,因为 0 不大于 13。在第二次迭代中,我们打印第 15 个字符,"O"
。继续这样做,直到我们到达 i=14
.
至此,"magic"开始。首先,我们尝试打印字符串的第 27 个字符。没有这样的字符,所以我们几乎什么都不打印。然后条件触发,我们进去。
i % 14
等于 0,所以我们打印第零个字符,"A"
。下一次迭代我们在索引 1 (15 % 14
) 处打印字符,依此类推,直到 .times
完成迭代并停止调用该块。现在,为了让这个逻辑起作用,i
的最后一个值必须 是 26,这样我们在 i % 14
中得到 12 并打印 "M"
。
整个字符串的长度是26。还记得吗,.times
是不包括数字的?这就是为什么我们在长度上加一,所以它从 0 计数到 26。这就是奥秘。
改进此代码的方法有很多,您会及时了解它们。 :)
更新
我知道 代码看起来有些奇怪。当然,还有一个错误。当 i
为 13 时,我们不会第一次打印 并且 我们不会进入条件。我们浪费了一次迭代。这是 "off by 1" class 错误的 classic 示例。这是固定版本的代码,不浪费迭代且不包含任何奥秘:
a.length.times do |i|
print a[i + 13]
if i > 12
print a[i % 13]
end
end
字符串的长度是26,但是索引是从0开始的。在这种情况下,字母 Z 的索引号为 25。times 方法不会 运行 最后一次迭代(26)。因此,为了解决这个问题,我们在长度上加了一个 +1。
我只需要一个快速的 rot13 one liner,这个 SO 条目是第一个 google 结果。我继续搜索并找到了@xfaider 的一个超小的,它对我的目的来说效果很好。
就post这里给下一个想要单线的人。
string.tr("A-Za-z", "N-ZA-Mn-za-m")
我做了一个简单的ROT13程序,有一点不明白:
a = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
(a.length+1).times do |i|
print a[i + 13]
if i>13
print a[i %14]
end
end
输出:
NOPQRSTUVWXYZABCDEFGHIJKLM
如果我不在 a.length
之后添加 +1
,则迭代以字母 L
结束。但是,如果我在迭代中使用 print a[i]
,它通常以 A
开始并以 Z
结束,不需要添加 +1
。
有人可以为我解释这个谜吗?
如您所知,.times
循环调用块指定次数,并在每次迭代中传递一个增量值。
如果我们说 26.times {|i| puts i}
它将打印从 0 到 25 的值。最多但不包括最后一个值。
现在让我们来看看这个循环。在第一次迭代中,i
为 0。因此我们打印字符串的第 14 个字符,"N"
(在索引 13 处,从零开始)。我们不进入条件,因为 0 不大于 13。在第二次迭代中,我们打印第 15 个字符,"O"
。继续这样做,直到我们到达 i=14
.
至此,"magic"开始。首先,我们尝试打印字符串的第 27 个字符。没有这样的字符,所以我们几乎什么都不打印。然后条件触发,我们进去。
i % 14
等于 0,所以我们打印第零个字符,"A"
。下一次迭代我们在索引 1 (15 % 14
) 处打印字符,依此类推,直到 .times
完成迭代并停止调用该块。现在,为了让这个逻辑起作用,i
的最后一个值必须 是 26,这样我们在 i % 14
中得到 12 并打印 "M"
。
整个字符串的长度是26。还记得吗,.times
是不包括数字的?这就是为什么我们在长度上加一,所以它从 0 计数到 26。这就是奥秘。
改进此代码的方法有很多,您会及时了解它们。 :)
更新
我知道 代码看起来有些奇怪。当然,还有一个错误。当 i
为 13 时,我们不会第一次打印 并且 我们不会进入条件。我们浪费了一次迭代。这是 "off by 1" class 错误的 classic 示例。这是固定版本的代码,不浪费迭代且不包含任何奥秘:
a.length.times do |i|
print a[i + 13]
if i > 12
print a[i % 13]
end
end
字符串的长度是26,但是索引是从0开始的。在这种情况下,字母 Z 的索引号为 25。times 方法不会 运行 最后一次迭代(26)。因此,为了解决这个问题,我们在长度上加了一个 +1。
我只需要一个快速的 rot13 one liner,这个 SO 条目是第一个 google 结果。我继续搜索并找到了@xfaider 的一个超小的,它对我的目的来说效果很好。
就post这里给下一个想要单线的人。
string.tr("A-Za-z", "N-ZA-Mn-za-m")