Python Vigenere 元组错误

Posted

技术标签:

【中文标题】Python Vigenere 元组错误【英文标题】:Python Vigenere tuple error 【发布时间】:2017-03-17 12:49:32 【问题描述】:

我正在尝试制作 Vigenere 密码。当我尝试加密消息时,出现以下错误。

    cipherCharIndexValue = baseAlphabet.index(keyList[keyIncrement]) + baseAlphabet.index(plainTextChar)
ValueError: tuple.index(x): x not in tuple

我不确定是什么问题导致了错误,有什么帮助吗?

baseAlphabet = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z')

plainText = input("Please enter the plain text")
key = input("Please enter the key word")
keyList = []
keyLength = 0
while keyLength < len(plainText):
    #Adds the users entered key into a list character by character. 
    #Also makes the key the same length as plainText
    for char in key:
        if keyLength < len(plainText):
            keyList.append(str(char))
            keyLength = keyLength + 1

#The variable each processed letter is appended to
completeCipherText = [] 
#This is the value used to temporaily store the ciphertext character during the iteration
cipherCharIndexValue = 0
keyIncrement = 0

#iterates through the plain text
for plainTextChar in plainText:
        #Adds the base alphabets index value of the key and the plain text char
        cipherCharIndexValue = baseAlphabet.index(keyList[keyIncrement]) + baseAlphabet.index(plainTextChar)
        while cipherCharIndexValue > 25:
             #makes the addition value under 26 as to not go out of range of base alphabet tuple
            cipherCharIndexValue = cipherCharIndexValue - 26 
         #appends the ciphertext character to the completeCipherText variable. 
         #The character is the index of the key + index of the       plainTextChar from baseAlphabet
        completeCipherText.append(baseAlphabet[cipherCharIndexValue])
         #Moves onto the next key
        keyIncrement = keyIncrement + 1
print ('').join(completeCipherText)#Makes the result a strings for printing to the console.

【问题讨论】:

我尝试运行您的代码并在第 2 行得到一个 IndentationError。在取消缩进包括第一个 while 循环的所有内容后,我在第 28 行得到一个 IndentationError。在取消缩进该行之后一个空格,我得到了NameError: name 'baseAlphabet' is not defined。请发一个minimal reproducible example 来证明你的问题。 keyList[keyIncrement]plainTextChar 不在 baseAlphabet 中。您需要进行一些故障排除才能确定究竟是哪个值失败了。 感谢您编辑代码。它现在为我运行。当我使用 Python 2 执行它,并为第一个提示输入 "foo" 并为第二个提示输入 "bar" 时,它运行时不会崩溃并输出 gof。请描述您输入的哪些输入导致程序崩溃。 考虑如果plainText(或keyList)包含一个不在baseAlphabet中的字符会发生什么。 【参考方案1】:

看来你使用的是python2.x,你应该使用raw_input而不是input

如果输入字符串中有空格或其他标点符号,你的代码会崩溃,所以我建议你在使用index方法之前确保keyList[keyIncrement]baseAlphabet中,如果它不在这个元组中,你会得到这个错误:

ValueError: tuple.index(x): x not in tuple

例如

if keyList[keyIncrement] in keyList:
    cipherCharIndexValue = baseAlphabet.index(keyList[keyIncrement]) + baseAlphabet.index(plainTextChar)

或者您可以使用try/catch 捕获异常以调试您的代码。

希望这会有所帮助。

【讨论】:

【参考方案2】:

每当您尝试获取不在baseAlphabet 中的字符的索引时,您都会收到ValueError: tuple.index(x): x not in tuple 错误。所以你需要确保key 只包含这样的字符,并且在编码plainText 时要么避免编码“坏”字符,而是将它们原封不动地复制到completeCipherText 列表中,或者将它们转换为有效的baseAlphabet 字符.

在传统加密中,将所有空格和标点符号转换为另一个字符是很常见的,例如'x''.'。我决定将'.' 添加到baseAlphabet 并编写一个小函数fix_string 来执行该操作。 fix_string 还确保所有字母都是小写的。

我还对您的代码做了一些其他小的简化。

baseAlphabet 没有必要成为一个元组。我们可以使用字符串。但是如果您确实想使用单个字符的元组,则无需完整地写出来,您只需将字符串传递给tuple 构造函数,例如

tuple("some string")

我们通常不需要跟踪列表、字符串等集合的长度。所有内置集合都跟踪自己的长度,我们可以使用len() 函数有效地访问该长度。

我们不需要keyIncrement。相反,我们可以使用zip 函数并行循环keyListplainText 的字符。

我们可以使用% 模数运算符,而不是使用循环来确保键和纯文本索引的总和在适当的范围内。

from __future__ import print_function

baseAlphabet = 'abcdefghijklmnopqrstuvwxyz.'

# Process s so that it only contains chars in baseAlphabet
def fix_string(s):
    # Convert to lower case
    s = s.lower()
    # Convert "other" chars to dot
    a = [ch if ch in baseAlphabet else '.' for ch in s]
    return ''.join(a)

# Vignere cipher
# mode = 1 to encode, -1 to decode
def vignere(plainText, key, mode):
    keyList = []
    while len(keyList) < len(plainText):
        # Adds the key into a list character by character. 
        # Also makes the key the same length as plainText
        for char in key:
            if len(keyList) < len(plainText):
                keyList.append(str(char))

    # The variable each processed letter is appended to
    completeCipherText = []

    # iterates through the plain text
    for keyChar, plainTextChar in zip(keyList, plainText):
        # Adds the base alphabet's index value of the plain text char and the key char
        cipherCharIndexValue = baseAlphabet.index(plainTextChar) 
        cipherCharIndexValue += mode * baseAlphabet.index(keyChar)
        # makes the addition value in range(len(baseAlphabet))
        cipherCharIndexValue = cipherCharIndexValue % len(baseAlphabet)

        # appends the ciphertext character to the completeCipherText variable. 
        # The character is the index of the key + index of the plainTextChar from baseAlphabet
        completeCipherText.append(baseAlphabet[cipherCharIndexValue])

    # Makes the result a string
    return ''.join(completeCipherText)

# Test

# plainText = raw_input("Please enter the plain text")
# key = raw_input("Please enter the key word")

plainText = 'This, is a test string!'
key = 'the key'

# Process plainText and key so that they only contain chars in baseAlphabet
plainText = fix_string(plainText)
key = fix_string(key)

ciphertext = vignere(plainText, key, 1)
print(ciphertext)

decoded = vignere(ciphertext, key, -1)
print(decoded)

输出

lomrjdfkgezciplgwsamkzg
this..is.a.test.string.

【讨论】:

以上是关于Python Vigenere 元组错误的主要内容,如果未能解决你的问题,请参考以下文章

维热内密码解密

NOIP 2012 题解

Vigenere 解密和取模

Go 语言入门很简单:实现 Vigenere 加密算法

Vigenere Cipher 没有错误消息 Python

Python Vigenere 代码重复错误