Search code examples
pythonpython-2.7encryptioncaesar-cipher

IndexError: list index out of range for the caesar cipher


I am making a Caesar cipher, and I get an out of index error when i run the code. It works and encrypts the message when it's a few letters, but when I enter in more than ten words it gives me an index error.

shift_key = int(raw_input("Enter in your key shift: 1-9\n>>> "))

alphabet = ['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']
encrypted_alphabet = []
encrypted_message = ''

for i in alphabet[shift_key:]:
    encrypted_alphabet.append(i)

input = raw_input("Enter text to be decoded\n>>> ").upper()
input = input.split()

for i in input:
    for j in i:
        index = alphabet.index(j)
        encrypted_message += encrypted_alphabet[index]
    encrypted_message += ' '
print encrypted_message  

Solution

  • The problem is in these two lines:

    for i in alphabet[shift_key:]:
        encrypted_alphabet.append(i)
    

    Notice that doing alphabet[shift_key:] slices the list alphabet to only take those elements starting from shift_key.

    In other words, if shift_key is 25, for example, then alphabet[shift_key:] returns just ['Y','Z']. Since you're appending these to encrypted_alphabet, encrypted_alphabet then becomes just ['Y','Z']. But what you want is also the rest of the alphabet appended to the end of encrypted_alphabet.

    Simply put, the lengths of your encrypted_alphabet and alphabet mismatch.

    You can correct it this very simply by

    for i in alphabet[shift_key:] + alphabet[:shift_key]:
        encrypted_alphabet.append(i)
    

    or (even more simply)

    encrypted_alphabet = alphabet[shift_key:] + alphabet[:shift_key]
    

    If you want to know the right way to do this, however, use the inbuilt string method maketrans instead, which is far simpler:

    import string
    
    shift_key = int(raw_input("Enter in your key shift: 1-9\n>>> "))
    
    alphabet = string.ascii_uppercase
    encrypted_alphabet = alphabet[shift_key:] + alphabet[:shift_key]
    caesar = string.maketrans(alphabet,encrypted_alphabet)
    input = raw_input("Enter text to be decoded\n>>> ").upper()
    
    print(input.translate(caesar))
    

    Quick explanation

    As the code indicates, maketrans creates a translation table between two strings, mapping each character in the first to the other. You can then feed this translation table into the .translate() method that every string has.