凯撒密码 - Python实现中的问题

3

您好,感谢提前回答问题。我正在尝试完成PythonChallenge的第一个任务:http://www.pythonchallenge.com/pc/def/map.html,并且对代码有几个问题。我知道这段代码是有效的:

import string
letters = string.ascii_lowercase
uletters = string.ascii_uppercase
text = ("g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj.")
for x in range(0, 26):
    text = text.replace(letters[x-2], uletters[x])
    print(text.lower())

我稍微调试了一下代码,以下是我的观察结果,也有一些问题需要解答: 1. 当我运行:

text = text.replace(letters[x], uletters[x+2])

错误会出现,例如将“translate”写成“trynslyte”。为什么这种变化会造成如此大的影响? 2. 当我将以下代码: uletters = string.ascii_uppercase 更改为

uletters = string.ascii_lowercase

出现了一堆“z”和“y”。再次问,问题是什么?

非常感谢

4个回答

4
当你评估letters[x-2]x为0或1时,你会得到letters[-1]letters[-2],在Python中分别访问最后一个和倒数第二个元素。这就是为什么这一步起作用的原因。然而,大于最后一个元素索引的索引没有同样的效果,所以当x太大时,letters[x+2]将不起作用。
你需要做的是像这样:
letters[(x+2)%len(letters)]

为了强制换行,请使用以下方法。

另一种方法就是将 letters = string.ascii_lowercase * 2 - kindall

1
更好的方法是使用str.translate()
from string import ascii_lowercase as lc

text = ("g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. "
        "bmgle gr gl zw fylb gq glcddgagclr ylb rfyr'q ufw rfgq rcvr gq qm jmle. "
        "sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj.")

print (text.translate(str.maketrans(lc, lc[2:] + lc[:2])))

要编写一个编码器,只需交换 maketrans() 的参数即可:

print (text.translate(str.maketrans(lc[2:] + lc[:2], lc)))

0
根据维基百科,凯撒密码是这两个数学同余方程:
E_n(x) ≡ (x + n) mod 26
D_n(x) ≡ (x - n) mod 26

其中E_n()是加密算法,D_n(x)是解密算法,x是明文或密文的一位,n是密钥,26是整数环的大小。所以,编写一个执行凯撒密码的程序最简单的方法就是...实现上述算法。

在计算机上进行这个操作时唯一的复杂性在于你不是在整数025之间进行运算,而是在两个整数范围上进行运算,因为你将整数解释为ASCII表中的字符。大写字母表示整数6590,小写字母表示整数97122

幸运的是,Python提供了两个函数可以将ASCII字符转换为整数,也可以将整数转换回ASCII字符:

>>> ord('a')
97
>>> chr(97)
'a'

您可以利用这个来保留您的案例。我将把ord作为参数的默认值传递进去,但是ASCII不会很快改变。然而,这确实让您加密不同的字符而不更改代码。

def E(x, n, m=26, upper_ord=ord('A'), lower_ord=ord('a')):
    if x.isupper():
        return chr(((ord(x) - upper_ord + n) % m) + upper_ord)
    else:
        return chr(((ord(x) - lower_ord + n) % m) + upper_ord)

def D(x, n, m=26, upper_ord=ord('A'), lower_ord=ord('a')):
    return E(x, -n, m, upper_ord, lower_ord)

>>> E('b', 3)
'e'
>>> E('b', 25)
'a'
>>> E('b', -3)
'y'
>>> E('e', -3)
'b'
>>> E('Q', 15)
'F'
>>> plaintext = "The quick brown fox jumps over the lazy dog"
>>> ciphertext = " ".join(map(lambda w: "".join(E(x, 2) for x in w), (word for word in 
sentence.split())))
>>> ciphertext
'Vjg swkem dtqyp hqz lworu qxgt vjg ncba fqi'
>>> decrypted = " ".join(map(lambda w: "".join(D(x, 2) for x in w), (word for word in 
ciphertext.split())))
>>> decrypted
'The quick brown fox jumps over the lazy dog'

在我看来,使用子索引偏移是牵强附会的。数学公式已经定义得很清楚了,所以直接使用它就好了!


0

你需要处理环绕问题。如果 x-2 小于 0,你会得到错误。


不,这个方向没问题。问题出在x+2太大了。 - Gustav Larsson
你是对的。我注意到这通常是一个环绕问题。 - Jiminion

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接