I'm trying to make a Vigenere cipher. When I try to encrypt the message I get the following error.
cipherCharIndexValue = baseAlphabet.index(keyList[keyIncrement]) + baseAlphabet.index(plainTextChar)
ValueError: tuple.index(x): x not in tuple
I'm not sure what is wrong is causing the error any help?
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.
You will get that ValueError: tuple.index(x): x not in tuple
error whenever you attempt to get the index of a char that's not in baseAlphabet
. So you need to make sure that key
only contain such chars, and when encoding plainText
either avoid encoding "bad" chars and just copy them to the completeCipherText
list unchanged, or convert them to a valid baseAlphabet
char.
In traditional encryption it was common to convert all spaces and punctuation to another character, eg 'x'
or '.'
. I decided to add '.'
to baseAlphabet
and write a small function fix_string
to perform that operation. fix_string
also ensures that all the letters are lower case.
I've also made a few other minor simplifications to your code.
There's no need for baseAlphabet
to be a tuple. We can use a string. But if you do want to use a tuple of single chars there's no need to write it out in full, you can just pass a string to the tuple
constructor, eg
tuple("some string")
We generally don't need to keep track of the length of collections like lists, strings, etc. All of the built-in collections track their own length and we can efficiently access that length with the len()
function.
We don't need keyIncrement
. Instead, we can loop over the chars of keyList
and plainText
in parallel by using the zip
function.
And instead of using a loop to ensure that the sum of the key and plainText indices are in the proper range we can use the %
modulus operator.
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)
output
lomrjdfkgezciplgwsamkzg
this..is.a.test.string.