我一直在读Allen B. Downey的“Think Python”,并且在其中有一个练习(8.12),作者要求创建一个ROT13函数。我做了我的,它部分起作用,因为我正在与大箱子挣扎。
以下是作者提供的解决方案的一部分:
def rotate_letter(letter, n):
"""Rotates a letter by n places. Does not change other chars.
letter: single-letter string
n: int
Returns: single-letter string
"""
if letter.isupper():
start = ord('A')
elif letter.islower():
start = ord('a')
else:
return letter
c = ord(letter) - start
i = (c + n) % 26 + start
return chr(i)
这里使用模数使得函数适用于大写字母,但我无法理解为什么! 很明显,通过使用它我们在ASCII值的开头重新开始大写,但我无法想出它背后的机制。
答案 0 :(得分:2)
尝试将其分解为步骤,然后打印出中间数字。或者,更好的是,在online visualizer中运行它。
比如说,'Q'
字母和数字13,你最终会得到:
'Q'.isupper() is true
start = ord('A') = 65
c = ord('Q') - start = 81 - 65 = 16
i = (c + n) % 26 + start = (16 + 13) % 26 + 65 = 29 % 26 + 65 = 3 + 65 = 68
chr(i) is 'D'
正如您所看到的,神奇的部分是(16 + 13) % 26
。因此,让我们尝试在从0(对于A
)到25(对于Z
)的每个数字上运行它,看看会发生什么:
>>> for i in range(26):
... print ((i + 13) % 26),
13 14 15 16 17 18 19 20 21 22 23 24 25 0 1 2 3 4 5 6 7 8 9 10 11 12
添加,然后将余数用26,意味着当你到达26时你会回到0。就像在23:00加1小时就可以让你在00:00时钟(或者,如果你&# 39;再来一个美国人,加上1小时到12点就可以到达1点。
答案 1 :(得分:2)
模26本身与大写和小写无关,需要使序列回到开头。
考虑一个简单的“腐烂1”:将字母表中的字母视为1到26之间的数字,然后加1.如果输入为'a',则取1 + 1 = 2并得到'b';如果输入为'z',则取26 + 1 = 27 - 但字母表中没有第27个字母!所以你计算27 mod 26 = 1,它“旋转”回'a'。
上面实现中大写和小写的实际技巧是start
的定义,它在应用旋转之前将ASCII位置转换为数字1到26,然后使用相同的偏移量将结果返回。