我正在尝试用Python做一个简单的Caesar密码。我的加密有效,但解密函数会给出字符串索引超出范围的错误消息。我已附上我的代码。欢迎任何评论。
import random
symbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!?@#$%^&*()' "
def encrypt_symbols(message, key):
encrypted = ''
index = 0
for letter in message:
index = symbols.find(letter) + key
if index > len(symbols):
index = index - (len(symbols) + 1)
encrypted = encrypted + symbols[index]
return encrypted
def decrypt(message, key):
decrypted = ''
index = 0
for letter in message:
index = symbols.find(letter) - key
if index < len(symbols):
index = index + len(symbols)
decrypted = decrypted + symbols[index]
return decrypted
test = "Wow! This works well, don't you think so?"
key = random.randrange(1, len(symbols))
secret_message = encrypt_symbols(test, key)
print(encrypt_symbols(test, key))
print(decrypt(secret_message, key))
最大的问题是不理解组/模运算和一些一次性错误。
在加密操作中:
if index > len(symbols):
索引从零开始,所以如果你有一个包含26个字符的普通ABC字母表,然后是Z
,那么索引最高的字符将位于索引25。在上述代码中,假设最高索引为26;您需要使用>=
。
index = index - (len(symbols) + 1)
我有一个强烈的想法,这是为了弥补以前的错误,但失败了。大小为N的组中的任何运算都将使用模N运算。换句话说,对于ABC,这里减去N=26,而不是N=27,应该删除+ 1
(以及一对括号,因为它们不再需要了)。
在解密操作中:
if index < len(symbols):
这是错误的假设;在[0,N)范围内的指数是可以的。你需要在这里与zero进行比较,因为减法可能会导致负值。
index = index + len(symbols)
现在,这就是错误发生的地方,因为您现在试图修复已经在正确范围内的值。幸运的是,您正确地使用了len(symbols)
而不是len(symbols) + 1
。
通常,我们使用模运算符对群运算符进行编程。
所以你只需要:
index = (symbols.find(letter) + key) % len(symbols)
加密期间,以及:
index = (symbols.find(letter) - key) % len(symbols)
在解密期间-没有任何if
语句。但是,由于您现在已经实现了组操作,您还可以输入加密例程-key
而不是key
,并获得解密例程";免费";。
备注:
- 其他(基于C的)语言,如Java,可能会让
%
表示余数,这可能会产生负面结果,所以你必须使用另一个mod
函数——幸运的是,Python使用了实际的模运算 - 如果要在一个组中进行乘法或求幂,那么出于效率原因,应该使用
modmul
或modpow
(即Python中有3个参数的pow()
)等函数
假设您的symbol[letter]
是"a",键是2,你的加密会给你"a"+2="c",这是正确的
但用于解密index = symbols.find('c') - key
=1但是,您将符号的长度添加到索引中,并超出的范围
if index < len(symbols)
index = index + len(symbols)
而你实际上超出了范围你可以代替if index < len(symbols)
if index < 0
首先,您需要更换
index = index - (len(symbols) + 1)
带有
index = index - (len(symbols))
在您的encrypt_symbols函数中,然后用以下代码替换您的解密函数:
def decrypt(message, key):
decrypted = ''
index = 0
for letter in message:
index = symbols.find(letter) - key
if index < len(symbols):
index = index + (len(symbols))
index = (index%len(symbols))
decrypted = decrypted + symbols[index]
return decrypted
在这里,我使用了模(%)来获得secret_message的各个字母的余数。
此外,替换字母的最佳实践是使用模数并避免加法/减法。
使用模数供您参考的代码:
def encrypt_symbols(message, key):
encrypted = ''
index = 0
for letter in message:
index = symbols.find(letter) + key
if index > len(symbols):
index = (index%len(symbols))
encrypted = encrypted + symbols[index]
return encrypted
和
def decrypt(message, key):
decrypted = ''
index = 0
for letter in message:
index = symbols.find(letter) - key
if index < len(symbols):
index = (index%len(symbols))
decrypted = decrypted + symbols[index]
return decrypted
请确保包含所有符号,否则find将用空格替换它。
我使用了以下
symbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!?@#$%^&*()', "