Build a dictionary for Caesar cipher

Assume a message is entered and you want to encrypt it by moving each letter in the word "up the alphabet" with a x number of spaces. eg "cat" moved one space becomes "dbu":

I am trying to build a dictionary with the alphabet in upper and lower case as the keys, and a duplicate alphabet (moved on "shift" number of letters) as the values. eg shift=1 d={a:b, b:c...A:B, B:C}. This alphabet changes every time "shift" changes. Please let me know where I am going wrong. Please see: def build_shift_dict(self, shift) below. Thanks in advance!:

class Message(object):
### DO NOT MODIFY THIS METHOD ###
def __init__(self, text):
    '''
    Initializes a Message object
            
    text (string): the message's text

    a Message object has two attributes:
        self.message_text (string, determined by input text)
        self.valid_words (list, determined using helper function load_words
    '''
    self.message_text = text
    self.valid_words = load_words(WORDLIST_FILENAME)

### DO NOT MODIFY THIS METHOD ###
def get_message_text(self):
    '''
    Used to safely access self.message_text outside of the class
    
    Returns: self.message_text
    '''
    return self.message_text

### DO NOT MODIFY THIS METHOD ###
def get_valid_words(self):
    '''
    Used to safely access a copy of self.valid_words outside of the class
    
    Returns: a COPY of self.valid_words
    '''
    return self.valid_words[:]
    
import string    
def build_shift_dict(self, shift):
    '''
    Creates a dictionary that can be used to apply a cipher to a letter.
    The dictionary maps every uppercase and lowercase letter to a
    character shifted down the alphabet by the input shift. The dictionary
    should have 52 keys of all the uppercase letters and all the lowercase
    letters only.        
    
    shift (integer): the amount by which to shift every letter of the 
    alphabet. 0 <= shift < 26

    Returns: a dictionary mapping a letter (string) to 
             another letter (string). 
    '''
    stringLower = string.ascii_lowercase 
    stringUpper = string.ascii_uppercase
    Alphabet = list(stringLower + stringUpper)
    dictionary = {}
    string2Lower = list(string.ascii_lowercase[shift:] + string.ascii_lowercase[0:shift])
    string2Upper = list(string.ascii_uppercase[shift:] + string.ascii_uppercase[0:shift])
    combinedList = string2Lower.append(string2Upper)
    
    for key in Alphabet: 
        for value in combinedList: 
            dictionary[key] = value 
            combinedList.remove(value) 
             
    return dictionary
    

    
    

def apply_shift(self, shift):
    '''
    Applies the Caesar Cipher to self.message_text with the input shift.
    Creates a new string that is self.message_text shifted down the
    alphabet by some number of characters determined by the input shift        
    
    shift (integer): the shift with which to encrypt the message.
    0 <= shift < 26

    Returns: the message text (string) in which every character is shifted
         down the alphabet by the input shift
    '''
    result=''
    dictionary = self.build_shift_dict(shift)
    messageString = str(Message)
    for letter in messageString:
        if letter in dictionary.keys:
         result += dictionary[i]
    return result

Upvotes: 0

Views: 2741

Answers (2)

Luke Storry
Luke Storry

Reputation: 6712

You can cut a lot of the class based stuff out, as it isn't doing much apart from adding boilerplate code and complicating things. You can put it back in after, but Here I've written the core functionality out for you in a more pythonic way:

import string

def build_shift_dict(shift):

    alphabet = string.ascii_lowercase + string.ascii_uppercase

    shifted_lower = string.ascii_lowercase[shift:] + string.ascii_lowercase[0:shift]
    shifted_upper = string.ascii_uppercase[shift:] + string.ascii_uppercase[0:shift]

    shifted_alphabet = shifted_lower + shifted_upper

    return {key: value for key, value in zip(alphabet, shifted_alphabet)}

Once you've got shifted_alphabet, you can zip it with the original alphabet, and then use a Dictionary Comprehension to create the dictionary. That's a much more pythonic way of making a dict, instead of a for loop


Then to apply the shift, we can use a list comprehension to lookup the dictionary for each letter in the message, and create a list, which is then join-ed back together into a string, and returned.

def apply_shift(shift, message):
    dictionary = build_shift_dict(shift)

    return ''.join(dictionary[letter] for letter in message)

Then to use:

>>> print(apply_shift(2, "Hello"))
Jgnnq

Available here -> https://repl.it/@LukeStorry/63042493


Update: You can avoid creating and using a dict by using ord and chr instead:

def apply_shift_v2(shift, message):
    return ''.join(chr(ord(letter) + shift) for letter in message)

This has the added bonus of working for any character, not just being limited to the alphanumeric ones you set up the dict with.

Upvotes: 2

klv0000
klv0000

Reputation: 174

my suggestion is instead of creating dictionary this will be lot simpler

def apply_shift(shift, letter):
    asci = ord(letter)
    new_ascii = 97 + (asci + shift -97) % 26
    return chr(new_ascii)

print(apply_shift(1, 'z') )

output:

a

Upvotes: 0

Related Questions