-1

I'm trying to have a function use the autokey cipher to encrypt a message. The function has an if statement telling it whether to use the uppercase ASCII letters or lower case. I do not understand why that if statement is not working. If the letter getting ciphered is lowercase, it should use the lowercase list, but that is not the case and it keeps using the upper case list to try to cipher it, which gives me an error since the letter is not an element in the list.

import string
# This is the variable that will hold the list of the alphabet
alphau = list(string.ascii_uppercase)
alphal = list(string.ascii_lowercase)
punctuation=list(string.punctuation)

# This is the encryption function
def encrypt(plaintext,key):
    enc = ''
    i = 0
    for letter in plaintext:
        if letter == ' ':
            enc += ' '
        elif letter =='\n':
            enc += '\n'
        else:
            if letter in alphal:
                x = (alphal.index(letter)+alphal.index(key[i]))%26
                i += 1 
                enc += alphal[x]
                x = ''
            if letter in alphau:
                x = (alphau.index(letter)+alphau.index(key[i]))%26
                i += 1 
                enc += alphau[x]
                x = ''
            if letter not in alphal or alphau:
                enc += letter
    return enc

msg=encrypt("MyNameIsMhegazy","jMiXMyNameIsMahm")
print(msg)
Traceback (most recent call last):
  File "c:\Users\User\Documents\GitHub\Coursework-1\encrypt.py", line 41, in <module>
    msg=encrypt("MyNameIsMahmoud",key1)
  File "c:\Users\User\Documents\GitHub\Coursework-1\encrypt.py", line 25, in encrypt
    x = (alphau.index(letter)+alphau.index(key[i]))%26
ValueError: 'j' is not in list

I have tried using the lists in other if statements and they are working fine. Also tried putting strings and having a for loop separate upper from lower case letters using the lists and that has also worked fine. I am not sure what the problem is with the code posted above. Thanks For Your Help!

Michael Delgado
  • 13,789
  • 3
  • 29
  • 54
Mhegazy
  • 1
  • 1
  • 2
    1. This is probably not what you wanted to write: `letter not in alphal or alphau`. This is most likely what you meant to write: `letter not in alphal or letter not in alphau`; 2. Consider using the `elif` instead of a bunch of separated `if` blocks; 3. Why do write `x = ''`?; 4. **The cause of the error:** At the first letter `M`, `key[i]` points to the letter `j`. So while `M` is an upper case letter, `j` is lowercase. You're just checking if `letter in alphau`, not also if `key[i] in alphau`, that's why it causes an error. – Carl HR Oct 29 '22 at 23:57
  • 1
    Once you do what number 2 of what @CarlHR said, number 1 of what they wrote can just be `else`. EDIT: [Tim Roberts](https://stackoverflow.com/users/1883316/tim-roberts) just said this in his answer below. – Finn E Oct 30 '22 at 00:01
  • Read [this article](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) for tips on debugging your code. – Code-Apprentice Oct 30 '22 at 00:05
  • The error happens because, when you have an upper case letter in your plaintext, you are trying to look up the corresponding key letter in upper case. There is no guarantee that each uppercase letter corresponds to an uppercase key letter. – Tim Roberts Oct 30 '22 at 00:09
  • As I said below, the 1st two if statements are redundant. Once you convert all of the `if` statements to `elif` ones, the 1st two conditions are captured by the last `else`. – Finn E Oct 30 '22 at 00:09
  • 1
    @Code-Apprentice -- Although he has committed that common mistake, that is not the cause of his error. – Tim Roberts Oct 30 '22 at 00:12
  • @TimRoberts Good point. I got hung up on just that when there's more to fix before that becomes a problem. – Code-Apprentice Oct 30 '22 at 00:17
  • In general, an interactive [debugger](/q/25385173/90527) is your most powerful tool in cases like this, for troubleshooting unexpected behavior and crashes. Find and learn to use whatever debugger your development suite provides. – outis Oct 30 '22 at 12:02

2 Answers2

1

Nothing wrong with the if statement, its your algorithm that needs a little tweaking. Take a look at this statement for example:

(alphau.index(letter)+alphau.index(key[i]))%26

as per your input

plaintext = "MyNameIsMhegazy"
key = "jMiXMyNameIsMahm"

on the first iteration, the letter is "M", i = 0, so key[i] = "j". Now you are trying to lookup the value of "j" in alphau which raises a ValueError.

What you can do is check further where the value of key[i] lies in, then use that list for lookup.

Michael Delgado
  • 13,789
  • 3
  • 29
  • 54
0

You only want one clause to match, so this needs to be a series of if/elif/elif clauses, like this:

def encrypt(plaintext,key):
    enc = ''
    i = 0
    for letter in plaintext:
        if letter == ' ':
            enc += ' '
        elif letter =='\n':
            enc += '\n'
        elif letter in alphal:
            x = (alphal.index(letter)+alphal.index(key[i]))%26
            i += 1 
            enc += alphal[x]
        elif letter in alphau:
            x = (alphau.index(letter)+alphau.index(key[i]))%26
            i += 1 
            enc += alphau[x]
        else:
            enc += letter
    return enc

You can skip the index call by just converting the letter to its ASCII equivalent.

def encrypt(plaintext,key):
    enc = ''
    i = 0
    for letter in plaintext:
        if key[i] < 'a':
            keyidx = ord(key[i])-'A'
        else:
            keyidx = ord(key[i])-'a' 
        if letter == ' ':
            enc += ' '
        elif letter =='\n':
            enc += '\n'
        elif letter in alphal:
            x = (ord(letter) - ord('a') + keyidx) % 26
            i += 1 
            enc += alphal[x]
        elif letter in alphau:
            x = (ord(letter) - ord('A') + keyidx) % 26
            i += 1 
            enc += alphau[x]
        else:
            enc += letter
    return enc
Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
  • While it does improve the code, I would argue that this does not actually solve the problem. Perhaps I have misunderstood your solution though. – Finn E Oct 30 '22 at 00:06
  • The first two if/elif statements are redundant. They would be captured by the `else` at the end. – Finn E Oct 30 '22 at 00:08
  • 1
    I would argue that this solves the problem exactly. This does successfully what the original code was TRYING to do. Your point about redundancy is correct. Left as an exercise for the reader. – Tim Roberts Oct 30 '22 at 00:10
  • Thanks for your help, but the function above still gives me the same error: ``Traceback (most recent call last): File "c:\Users\User\Documents\GitHub\Coursework-1\encrypt.py", line 35, in msg=encrypt("MyNameIsMahmoud",key1) File "c:\Users\User\Documents\GitHub\Coursework-1\encrypt.py", line 28, in encrypt x = (alphau.index(letter)+alphau.index(key[i]))%26 ValueError: 'j' is not in list`` – Mhegazy Oct 30 '22 at 00:14
  • I have tried the solution without the `index` call, and it seems to have worked. However I would still like to know why the index call was not working with the if statement and not causing it to skip to the next condition. Thanks a lot! – Mhegazy Oct 30 '22 at 00:21
  • At least three people have told you why. If the plaintext letter is lowercase, you are looking up the current key letter in lowercase, but there's no reason to expect the key to be lowercase. Your plaintext starts with an uppercase M. You then try to look up the key letter, lowercase `j`, in the uppercase string. That fails. – Tim Roberts Oct 30 '22 at 00:23
  • @FinnE is right, I was not implementing the same algorithm. I was adding the key index, not the key letter. I have fixed that. – Tim Roberts Oct 30 '22 at 00:26