Search code examples
pythoncaesar-ciphervigenere

Python Vigenere Cipher with required functions


I am working on an online course that has us creating a caesar cipher and vigenere cipher, but we first created two functions; one to find the position of a letter in an alphabet variable, and one to rotate one given character a given amount of times (I have seen that ord() and chr() work better, but the assignment wants us to focus on simpler concepts for now, I guess).

I was able to get the caesar function working, but am unsure as how to go forward with the vigenere cipher. I have watched many videos and looked around this site, but have not found any that allow for the preservation of spaces and non alphabetical characters. Can anyone point me in the right direction of how to start the vigenere function?

#Create function alphabet_position(letter) to turn letter into number
#such as a=0 or e=4, using lowercase to make sure case doesnt matter.
def alphabet_position(letter):
    alphabet ="abcdefghijklmnopqrstuvwxyz" #Lists alphabet for a key
    lower_letter = letter.lower()   #Makes any input lowercase.
    return alphabet.index(lower_letter) #Returns the position of input as a number.

def rotate_character(char, rot):
    alphabet = "abcdefghijklmnopqrstuvwxyz"
    if char.isalpha():
        a = alphabet_position(char)
        a = (a + rot) % 26            #needs modulo
        a = (alphabet[a])
        if char.isupper():
            a = a.title()
        return a
    else:
       return char

def encrypt(text, rot):
    list1 = ""
    for char in text:
        list1 += rotate_character(char, rot)
    return list1



def main():
    x = input("Type a message: ")
    y = input("Rotate by: ")
    #result = rotate_character(x, y)  #Not needed once encrypt function works.
    result = encrypt(x, y)
    print (result)

if __name__ == '__main__':
    main()

Solution

  • following my comments; using all printables as alphabet:

    from string import ascii_letters, digits, punctuation, whitespace
    
    ALPHABET = ascii_letters + digits
    STATIC_ALPHABET = punctuation + whitespace
    
    # minor speedup
    ALPHA_INDEX = {a: i for i, a in enumerate(ALPHABET)}
    STATIC_ALPHABET_SET = set(STATIC_ALPHABET)
    MOD = len(ALPHABET)
    
    def encrypt(char, key):
        if char in STATIC_ALPHABET_SET:
            return char
        else:
            return ALPHABET[(ALPHA_INDEX[char] + key) % MOD]
    
    def decrypt(char, key):
        if char in STATIC_ALPHABET_SET:
            return char
        else:
            return ALPHABET[(ALPHA_INDEX[char] + MOD - key) % MOD]
    
    key = 17
    plain = 'Hello World!'
    enc = ''.join(encrypt(char, key) for char in plain)
    print(enc)  # YvCCF dFICu!
    dec = ''.join(decrypt(char, key) for char in enc)
    print(dec)  # Hello World!