当使用 Python 解密时,ROT2 密码导致与预期字符不同的字符

ROT2 cipher resulting in different than expected characters when deciphered with Python

我从 Pythonchallenge 网站

上解谜语很开心

当我偶然发现一个奇怪的行为时:

有了这个输入: *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。 sqlgle qrpgle.kyicrpylq() gq pcamkkclbcb。 lmu ynnjw ml rfc spj.

我们应该能够得到以下输出: *“我希望你没有手工翻译它。这就是计算机的用途。手工翻译效率低下,这就是为什么这篇文章这么长。建议使用 string.maketrans()。现在申请 url。” *

相反,当我们用一个简单的 ROT2 脚本破译它时,我们得到的是: 我希望你没有 tr{nsl{te it |y h{nd0 th{ts wh{t computers {re for0 doing it in |y h{nd is inefficient {nd th{t)s why this text is so long0 using string0m{ketr{ns+ is recommended0 now {apply on the url0*

我引用的 ROT2 脚本是 follows:

user_input = input().split(' ')
newletter_int = 0
new_output = []

for word in user_input:
    newletter_int = 0 
    newstr = ''

    for letter in word:
        newletter = ord(letter) + 2
        newstr += chr(newletter)
    new_output.append(newstr)
print(" ".join(new_output))

这当然是自然发生的,因为字母“y”的序号为 121,当我们将 2 加到 121 上时,我们得到序号为 123 的字符“{”。但是为什么 Python maketrans 会产生正确的字符呢?

请注意,我已经用 maketrans 解决了这个任务,我正在寻找的不是谜语的解决方案,因为我已经能够自己找到它了。我正在寻找一个简单的解释,这两种方法有什么区别。另外,请不要参考解决方案链接的页面,因为我不是在寻找它们,而是为了解释我上面的脚本和 string.maketrans() 方法之间的功能差异,还有一个回答为什么这是解决谜语的推荐方法。

But why would then the Python maketrans result in the correct character?

makeTrans 只是提供了一种遍历字符的方法;最后传递的映射仍然取决于提供的字典/输入参数。

如果它传递一个映射,将 Y 映射到 A 进行加密,将 A 映射到 Y 进行解密,那么 makeTrans 显然工作正常,因为字典 已经包含环绕 你忘记申请了。

所以你定义的函数映射:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
CDEFGHIJKLMNOPQRSTUVWXYZ{|

而它应该执行以下加密映射:

ABCDEFGHIJKLMNOPQRSTUVWXYZ
CDEFGHIJKLMNOPQRSTUVWXYZAB

makeTrans 只是接收正确的映射(如果您不指定第三个参数,则其他字符保持原样)。


请注意,执行环绕的好方法是将字母转换为提供的字母表中的索引,然后使用取模运算符执行环绕:% 而不是对直接使用 ASCII 值(因此 A 映射到 0 而不是十进制的 97)。

我假设您在使用 str.maketrans 时专门在字母之间创建了 映射 table。 这正是重点:您在字符之间指定了一个 1 对 1 的映射,因此可以保证这些转换会按照您指定的方式发生。

现在让我们看看您的脚本:

  1. 您正在使用 ord,其中 returns 一个表示您传递给它的字符的 Unicode 代码点的整数。 这本质上意味着我们应该对字符编码有一些基本的了解。 对于这个问题,您可以忽略 Unicode 代码点,因为我们正在处理可以使用 ASCII 编码的字符(设计 Unicode 的聪明人确保前 256 个代码点是相同的)。 为了了解 ASCII 是怎么回事 table 将成为你最好的朋友:

  1. 现在让我们看看您的 ROT2 实施中最重要的一行:newletter = ord(letter) + 2。 看看上面的table,就应该明白为什么y会变成{,或者为什么.会变成0。 正因为如此,我们需要更聪明地实现我们的实现;具体来说,我们需要仔细研究我们跨越该界限的场景。 规避这种情况的一种常见方法是使用 (ord(letter) - 97 + 2) % 26 + 97 之类的东西。 我会让你弄明白为什么这对你自己有效。

  2. 我看到您正在使用 str.split 以避免转换空格。 不幸的是,这还不够,因为您要转换的字符串包含其他 非字母 ,例如 '.。 我建议你看一下 string module.

    提供的常量

至于为什么这可能是解决谜语的推荐方法,我猜这正是因为使用加法手动转换字符所涉及的所有工作。 正如我试图用我的答案来说明的那样,指定 1 对 1 字符映射 并将其直接应用于字符串要简单得多。