Python模运算符给出意想不到的结果

时间:2012-10-23 06:48:19

标签: python modulo

我是Python的新手,并且模数有问题。

以下是代码:

for i in range(ord('a'), ord('z')+1):
    print chr(((i+2) % 97) + 97 )

检测到的结果为cdef...a。但是,一旦到达z,我就无法获得所需的模块行为。

5 个答案:

答案 0 :(得分:6)

因为97不是你想要包装的东西 - 你希望在ord('z') = 122处包装,然后添加ord('a')(97)的值。

你真正需要做的完整数学运算是转移到偏移量,然后回到集合。例如......

for i in range(ord('z') - ord('a') + 1): # equivalent to range(26); i.e. 0-25
    print chr(((i+2) % 26) + ord('a')) # results in 2+97 'c', 3+97 'd', etc.

您现有代码无效的原因是因为i+2总是大于97(因为您的iord('a')开始,即97,并从那里上升),所以% 97实际上只是- 97,因此您的打印行实际上是这样的:

print chr(((i+2) - 97) + 97 )

减少到......

print chr((i+2) - 97 + 97)

显然只是print chr(i+2)

答案 1 :(得分:3)

你应该使用模26(英文字母中的字母数)。这段代码可以使用:

for i in range(ord('a'), ord('z') + 1):
   j = i - ord('a')
   print chr(ord('a') + (j + 2) % 26)

说明

考虑这个索引模板:

A + (j + B) % C

它会将j的不同值映射到范围A … (A + C - 1)。最初,您选择了A = 97C = 97,因此您要映射到范围97 … 193。我选择了A = ord('a') = 97C = 26,因此我映射到范围97 … 122,即ord('a') … ord('z')

现在关于偏移B。您想要向左旋转两个位置,因此您已正确选择B = 2。但是,为了使其正常工作,a作为第一个字母必须在轮换之前由0编码。因此j = i - ord('a')

答案 2 :(得分:1)

您需要将值调整为0-26范围,修改它,应用mod,然后再切换回正确的字符范围。这是多个步骤

for i in range(ord('a'), ord('z')+1):
    idx = i - ord('a')
    mod_idx = ( idx + 2 ) % 26
    c = chr( mod_idx + ord('a') )
    print( chr(c) )

这就是oneline(太丑陋的IMO)

for i in range(ord('a'), ord('z')+1):
    print( chr((( i - ord('a')) + 2 ) % 26 + ord('a')) )

答案 3 :(得分:1)

在处理mod时,从1以外的数字循环可能会让人感到困惑。这是你的代码重构为使用1作为起点。

for i in range(ord('a'), ord('z')+1):
    print chr( (i-97+2) % 26) + 97 ) #Subtract 97, do our modulo and shift, then add 97

答案 4 :(得分:1)

其他人已经回答了您的代码有什么问题。我想提出一个不必处理模数的解决方案。我认为这是一种更简洁的方法,因为您不必处理使用ordchr来回转换的细节。

即使您正在处理字符代码并非全部按顺序排列的外国字母表,它也可以正常工作。

>>> from string import ascii_lowercase
>>> from collections import deque
>>> chrs = deque(ascii_lowercase)
>>> chrs.rotate(-2)
>>> print "".join(chrs)
cdefghijklmnopqrstuvwxyzab

如果您打算将其用于某种翻译或编码,只需构建一个词典然后离开:

>>> tr = dict(zip(ascii_lowercase, chrs))
>>> "".join(tr.get(x, x) for x in "abcd xyz")
'cdef zab'