From charlesreid1

Goodrich Python Chapter 5 Questions

Q R-5.10 Caesar cipher constructor

Link: https://git.charlesreid1.com/cs/python/src/master/arrays/CaesarCipher.py

Modify the Caesar Cipher object constructor to initialize the offset forward/backward alphabets using a list comprehension.

Here are the two key lines from the constructor:

self._forward = ''.join([chr(ord('A') +((j + shift)%26))    for j in range(26)])
self._backward = ''.join([chr(ord('A')+((j - shift+26)%26)) for j in range(26)])

The expressions find the offset, beginning at the letter A (note that all strings passed in are made uppercase), that corresponds to the key "shift". Then we're adding (or subtracting) each sequential integer from 1 to 26, mod 26, so that we move in a circle.

Note that this does no error checking for non letter types, or symbols, or any of that. It's pretty awful in that respect, but it's mainly to illustrate list comprehension.

$ cat CaesarCipher.py
"""
Goodrich et al
Data Structures in Python
Chapter 5: Array-Based Sequences

Question R-10

Modify Caesar cipher class to have a 2-line constructor:
    build the fwd and backward strings using join and the
    appropriate list comprehension syntax
"""


class CaesarCipher:
    """Clas for encrypting/decrypting using Caeesar Cipher"""

    def __init__(self,shift):
        """Construct Caesar cipher with the given integer shift"""
        self._forward = ''.join([chr(ord('A') +((j + shift)%26))    for j in range(26)])
        self._backward = ''.join([chr(ord('A')+((j - shift+26)%26)) for j in range(26)])

    def encrypt(self,message):
        message = message.upper()
        return self._transform(message,self._forward)

    def decrypt(self,ciphertext):
        ciphertext = ciphertext.upper()
        return self._transform(ciphertext,self._backward)

    def _transform(self,original,code):
        msg = list(original)
        for k in range(len(msg)):
            if(msg[k].isupper()):
                j = ord(msg[k]) - ord('A')
                msg[k] = code[j]
        return ''.join(msg)

if __name__=="__main__":
    c = CaesarCipher(3)
    msg = "ALL GAUL IS DIVIDED INTO THREE PARTS"

    print("Orig: {0}".format(msg))
    coded = c.encrypt(msg)
    print("Secret: {0}".format(coded))
    plain = c.decrypt(coded)
    print("Decrypted: {0}".format(plain))

Output

$ python3 CaesarCipher.py
Orig: ALL GAUL IS DIVIDED INTO THREE PARTS
Secret: DOO JDXO LV GLYLGHG LQWR WKUHH SDUWV
Decrypted: ALL GAUL IS DIVIDED INTO THREE PARTS