-1

I am currently trying to write a program, for school, in order to encrypt and decrypt a inputted message. I need the encrypted or decrypted message to only be in the alphabet no other symbols or keys, for example, with an inputted offset of 5 using the message van to encrypt, i want it to output 'afs'. Can anyone help please? This is my code currently:

def find_offset():

    offset = int(input("Enter an offset: "))

    if offset > 25 or offset < 0:
        print("Invalid offset, please enter another offset: ")
        find_offset()
    else:
        print("Okay")
        encrypt_fun(offset)


def encrypt_fun(offset):

    choice = ''
    while choice != '3':
        choice = input("\nDo you want to encrypt or decrypt the message?\nEnter 1 to Encrypt, 2 to Decrypt, 3 to Exit Program: ")
        if choice == '1':
            message = input("\nEnter the message to encrypt: ")

            for i in range(0, len(message)):
                result = chr(ord(message[i]) + offset)
                print(result, end=''),

        elif choice == '2':
            message = input("\nEnter the message to decrypt: ")

            for i in range(0, len(message)):
                result = chr(ord(message[i]) - offset)
                print(result, end=''),

        elif choice != '3':
            print("You have entered an invalid choice. Please try again.\n\n")

find_offset()
miradulo
  • 28,857
  • 6
  • 80
  • 93

1 Answers1

0

Currently you don't do any bounds checking for if you go over or under the ordinal value of a (97) or z (122).

If you were to specify these conditions, and check when adding or subtracting your offset, you would find the result you're looking for.

LOWER_BOUND = 97
UPPER_BOUND = 122

def alter_char(char, offset):
    """
    Alter char will take a character as input, change the ordinal value as 
    per the offset supplied, and then perform some bounds checks to ensure
    it is still within the `a <-> z` ordinal range. If the value exceeds
    the range, it will wrap-around to ensure only alphabetic characters
    are used.

    :param str char: The character you wish to manipulate
    :param int offset: The offset with which to alter the character
    :return: Returns the altered character
    :rtype: str
    """
    char_ord = ord(char) + offset
    if char_ord > UPPER_BOUND:
        return chr(LOWER_BOUND + (char_ord - UPPER_BOUND) - 1)
    if char_ord < LOWER_BOUND:
        return chr(UPPER_BOUND - (LOWER_BOUND - char_ord) + 1)
    return chr(char_ord)

With that in place, you can alter your result = chr(ord(message[i]) + offset) lines to call the alter_char function to ascertain the character you're looking for, ie.

result = alter_char(message[i], offset)  # for encryption
result = alter_char(message[i], -offset) # for decryption
# Prefixing the offset with a `-` is functionally equivalent to multiplying
# the offset by `-1`

As an aside, strings are naturally iterable, so your for i in range loop can be refactored as such

for char in message:
    result = alter_char(char, offset)

or going a step further and turning it into a list comprehension

result = ''.join([alter_char(char, offset) for char in message])

Just note, that this will still only cater for lower case messages being submitted for encryption and decryption as UPPER CASE letters have different ordinal values.

Christian Witts
  • 11,375
  • 1
  • 33
  • 46