Python Vigenere 工作,但我无法使用函数解释空格和非字母字符

Python Vigenere working, but I can't account for the spaces and non alphabetical characters using functions

我目前正在为初学者 python 课程编写密码程序。我们首先被告知创建一个函数,该函数将 return 给定字母的位置,使用字母表的字符串作为参考(即我的 alphabet_position 函数)。接下来,我们被告知使一个允许单个字母按选定数字旋转的函数(即我的 rotate_character 函数)。第三,我们的任务是使用前两个函数创建一个基本的凯撒密码。正如下面的代码所示,我能够完成的所有工作。

然而,vigenere 证明要困难得多。我实际上能够找到一段代码,我可以用我的第一个函数(alphabet_position)修改它,以便在只使用字母字符的情况下工作,但是一旦我输入任何非字母字符(例如! 或 ?) 我得到一个 return 的 ValueError: Substring Not found。当程序遇到这些非字母字符时,密钥应该跳过它们并将密钥的第 N 个字符带到下一个字母字符。

我猜答案在于以某种方式将我的 rotate_character 函数合并到我的 Encrypt 函数中,但我不确定该怎么做,因为 rotate_character 函数需要一个字母字符,并且vigenere 函数在 运行 它通过之前将该参数转换为 int。

有什么建议吗?由于我是一名新程序员,我很乐意接受您可能想要灌输的任何其他对我的编码实践有帮助的批评!`

> #Create function alphabet_position(letter) to turn letter into number
> #such as a=0 or e=4, using lowercase to make sure case doesnt matter. 
  alphabet = "abcdefghijklmnopqrstuvwxyz" 
  def alphabet_position(letter):
>     lower_letter = letter.lower()   #Makes any input lowercase.
>     return alphabet.index(lower_letter) #Returns the position of input 
                                           as a number.
> 
> def rotate_character(char, rot):
>     if char.isalpha():
>         a = alphabet_position(char);
>         a = (a + rot) % (int(len(alphabet)));            #needs modulo
>         a = (alphabet[a]);
>         if char.isupper():
>             a = a.title()
>         return a
>     else:
>        return char
> 
> def caesar(text, rot):
>     list1 = ""
>     for char in text:
>         list1 += rotate_character(char, rot)
>     return list1
> 
> def vigenere(text,key):       
    m = len(key)
> 
>   newList = ""
> 
>   for i in range(len(text)):      
        text_position = alphabet_position(text[i])      
        key_position =  alphabet_position(key[i % m])       
        value = (text_position + key_position) % 26         
        newList += alphabet[value]      
    return newList
> 
> def main():
>     x = input("Type a message: ")
>     y = input("Rotate by: ")
>     result = vigenere(x, y)
>     print (result)
> 
> if __name__ == '__main__':   
      main()

不,您不再需要旋转功能。您只需要直接将任何不在字母表中的字符添加到新列表中,然后跳过加密部分。

现在一个次优的方法是使用 if ... in ...:

if text[i] in alphabet:
    # do your thing
else:
    newList += text[i]

当然更优化的是只遍历一次字母并使用一个变量:

pt_c = text[i]
pt_i = alphabet.find(pt_c) # returns -1 instead of an error when not found
if pt_i == -1:
    newList += pt_c
else:
    newList += pt_c
    # do your thing *with the given index*

当然,这不会对 Vigenère 密码的运行时间产生任何影响。但它向您展示了如何为以后的高效编程思考:无需搜索两次。

您也可以 continue 循环而不是 else 语句:

pt_c = text[i]
pt_i = alphabet.find(pt_c) # returns -1 instead of an error when not found
if pt_i == -1:
    continue
# do your thing with the given index

这将使循环的缩进深度(范围的数量)减少,不幸的副作用是使循环更复杂(创建本地退出点)。