无法弄清楚为什么我的字母在 Python 中的凯撒密码中没有旋转

cannot figure out why my letters are not rotating in the Caesar code in Python

我已经研究这个问题大约一个星期了,但无法弄清楚为什么我的字母没有旋转。我不是在找人为我编写代码,而是帮助我找出我的问题所在。基本上,我正在寻找一只橡皮鸭来帮助解决这个问题。我看到它旋转了最后一个字母,但没有旋转其余字母。这是我现在所在的位置。

from string import ascii_uppercase, ascii_lowercase

def caeser_encrypt(string, step):
    new_string = list(string)

    for i in range(len(new_string)):
        new_ascii = ord(new_string[i]) + step

    if string[i] in ascii_uppercase:
        if new_ascii > 90:
            new_ascii = new_ascii - 90 + 64
        elif new_ascii < 65:
            new_ascii = 91 - 65 - new_ascii

    if string[i] in ascii_lowercase:
        if new_ascii > 122:
            new_ascii = new_ascii - 122 + 96
        elif new_ascii < 97:
            new_ascii = 123 - 97 - new_ascii
        new_string[i] = chr(new_ascii)

    return ''.join(new_string)

def main ():
    string = input('Enter word(s)')
    step = input("How many rotations do you want?")
    step = int(step)

    print(caeser_encrypt(string, step))

if __name__ == "__main__":
    main()

那里有几个缩进问题:

  1. for i in range(len(new_string)):循环中只发生了一件事,即设置new_ascii。当该循环结束时,i 等于 len(new_string) - 1,因此它将设置最后一个字符,但不会设置任何其他字符。

  2. new_string[i] = chr(new_ascii) 行是您的代码向新字符串添加字母的位置,但请检查您的缩进 - 它仅在 if string[i] in ascii_lowercase: 为真时发生,因此仅适用于小写字母.

这应该有效:

def caeser_encrypt(string, step):
    new_string = list(string)

    for i in range(len(new_string)):
        new_ascii = ord(new_string[i]) + step

        if string[i] in ascii_uppercase:
            if new_ascii > 90:
                new_ascii = new_ascii - 90 + 64
            elif new_ascii < 65:
                new_ascii = 91 - 65 - new_ascii

        if string[i] in ascii_lowercase:
            if new_ascii > 122:
                new_ascii = new_ascii - 122 + 96
            elif new_ascii < 97:
                new_ascii = 123 - 97 - new_ascii

        new_string[i] = chr(new_ascii)

    return ''.join(new_string)

只有最后一个字母被旋转,因为这个缩进:

for i in range(len(new_string)):
    new_ascii = ord(new_string[i]) + step

if string[i] in ascii_uppercase:
    if new_ascii > 90:
        new_ascii = new_ascii - 90 + 64
    elif new_ascii < 65:
        new_ascii = 91 - 65 - new_ascii

你的意思是这样的:

for i in range(len(new_string)):
    new_ascii = ord(new_string[i]) + step

    if string[i] in ascii_uppercase:
        if new_ascii > 90:
            new_ascii = new_ascii - 90 + 64
        elif new_ascii < 65:
            new_ascii = 91 - 65 - new_ascii

也就是说,if语句应该在for语句下面缩进。 如果 if 语句没有那样缩进, 那么它们就不会在循环中执行, 但只执行一次, for 循环之后。 当时i设置为最后一个字母的索引, 这就是为什么只旋转最后一个字母的原因。

代码审查

许多其他改进都是可能的。

而不是像 90、65 这样的神奇数字, 最好使用 ord('z')ord('a').

if string[i] in ascii_uppercaseif string[i] in ascii_lowercase是互斥条件, 所以它们应该与 elif.

链接在一起

而不是 if string[i] in ascii_uppercase, 它在 ascii_uppercase 中执行线性搜索(检查 ascii_uppercase 中的每个值,直到找到匹配项), 使用范围检查会更有效, if 'A' <= string[i] <= 'Z'.

该实现也替换了非字母字符。 如果我想旋转"hello world", 这会给出一个有趣的结果, 因为 space。 也许这样也好, 这样单词边界就无法区分了。 所以这不是批评,只是旁注。

放在一起, 以及其他一些小的改进, 你可以这样写:

def caeser_encrypt(string, step):
    new_string = list(string)

    for i, c in enumerate(new_string):
        new_ascii = ord(c) + step

        if 'A' <= c <= 'Z':
            new_ascii = ord('A') + (new_ascii - ord('A')) % 26

        elif 'a' <= c <= 'z':
            new_ascii = ord('a') + (new_ascii - ord('a')) % 26

        new_string[i] = chr(new_ascii)

    return ''.join(new_string)