0

So when I encode "hello" in my Encode() function, with a shift of three I get the result "khoor". When I attempt to decode "khoor" using my decode function with a shift of three, I get "hellor". This is strange because an extra letter "r" is returned, despite only decoding 5 letters. This happens with every string I attempt to decode, and I have noticed that the last letter of every string to be encoded is added as an additional letter to the decoded string.

ALPHABET = 'abcdefghijklmnopqrstuvwxyz'

def Menu():
    print("Please choose from the following: \n")
    print("'e' to encode a string.")
    print("'d' to decode a string.")
    print("'q' to quit.\n")
    choice = input("Please enter one of the letters above.\n")
    if choice == "e":
        print (Encode())
    if choice == "d":
        print (Decode())
    if choice == "q":
        print("The program will now exit.")
        quit()

def stringValidation():
    while True:
        try:
            valid = str(input("Enter a string to encode.\n"))
            return valid
            break
        except:
            print("Value Error. Enter a string with only letters from the alphabet.")
            continue

def shiftValidation():
    while True:
        try:
            valid = int(input("Enter the number of shifts you would like.\n"))
            return valid
            break
        except:
            print("Value Error. Please enter an integer.")

def decodeShiftValidation():
    while True:
        try:
            valid = int(input("Enter the key. (Number of shifts used to encrypt the encoded word.)\n"))
            return valid
            break
        except:
            print("Value Error. Please enter an integer.")


def Encode():
    data = []
    string = stringValidation() # asks the user for the string input to be encoded
    shift = shiftValidation() # asks the user for the number of shifts
    for i in string:        # for the letters in string...
        if i.strip() and i in ALPHABET: # i.strip removes all default whitespace characters from i (string input by user.)
            data.append(ALPHABET[(ALPHABET.index(i) + shift) % 26]) # gets position of the letters from input string in ALPHABET using indexing, and adds the shift to get the new position and new letter.
        else:
            data.append(i) # if it is a space, simply append it to the data.
    output = ''.join(data)
    return output
    encoded_string= Encode()
    print(encoded_string)

def Decode():
    data = []
    string = input("Please enter the string you wish to decode.\n")
    shift = int(input("Enter the key. (Number of shifts used when encoding original word. \n"))
    for i in string:
        if i.strip() and i in ALPHABET:
            data.append(ALPHABET[(ALPHABET.index(i) - shift) % 26])
    else:
        data.append(i)
    output = ''.join(data)
    return output

Menu()
John
  • 13
  • 4

2 Answers2

2

An indentation error makes the else of your Decode function a else for the for loop (which is a lesser-known feature of for loop: if no break is encountered, the else executes, adding an extra letter in your case).

That explains why you don't get an error but unexpected behaviour.

More here: Why does python use 'else' after for and while loops?

Aside, a very clumsy way to search in the alphabet is to use index, when you can compute the index directly with characters codes:

data.append(ALPHABET[(ord(i)-ord(ALPHABET[0]) + shift) % 26])

Aside #2: note that decode & encode methods are very similar. Factorize them with the shift as parameter (which is the opposite from one method to the other)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
1

I got errors trying to run your script until I changed all of the input statements to raw_input. But I don't quite understand the logic behind if i.strip() and i in ALPHABET:. Also, you don't have to accumulate letters in a list one at a time and then join them back, when Python lets you append strings directly. In any case, when I simplified your Decode() function to the following, it worked for me:

def Decode():
    string = raw_input("Please enter the string you wish to decode.\n").lower().strip()
    if string.isalpha():
        shift = int(raw_input("Enter the key. (Number of shifts used when encoding original word. \n"))
        return ''.join([ ALPHABET[(ALPHABET.index(c) - shift) % 26] for c in string])

I also added in a .lower() and .isalpha() check in case the user uses any capital letters or non-alphabetic strings, but there are other things like this you can add to handle other use cases.

Bill M.
  • 1,388
  • 1
  • 8
  • 16