<jupyter_start><jupyter_text>Caesar CipherThis notebook introduces the Caesar cipher. A Caesar cipher is one of the easiest ways to encrypt text. It's also extremely easy to crack. But for the purposes of introducing ciphers, it's a great place to start. The setup is pretty simple. You start with a message that you want to codify so someone else cannot read it. Say the message is **"I hope you cannot read this."**. This is called the *plaintext*. Now we need to apply some algorithm to our text so the output is incoherent. For example, the output may be **O nuvk eua igttuz xkgj znoy."**.  What we did in this case is shift every letter six places to the right: A becomes G, B becomes H, Z becomes F, and so on. > **plaintext:**  I hope you cannot read this.  > **ciphertext:** O nuvk eua igttuz xkgj znoy.Right away we can see this particular setup is very easy to crack. It includes capitalization and the words are clearly split. By converting all the text to lowercase and removing all spacees, we can make it a bit more difficult. However, there are only 25 different ways to shift the letters. That means a brute force attack, or trying all possibilities, is trivial.Let's see what this looks like in code. We'll create a class called *CaesarCipher* that can encrypt or decrypt text.  ---<jupyter_code>class CaesarCipher:
    
    
    
    def _clean_text(self, text):
        '''converts text to lowercase, removes spaces, and removes punctuation.'''
        import string
        assert type(text) == str, 'input needs to be a string!'
        text = text.lower()
        text = text.replace(' ', '')
        self.clean_text = "".join(character for character in text 
                                  if character not in string.punctuation)
        return self.clean_text
    
    
    def _string2characters(self, text):
        '''converts a string to individual characters.'''
        assert type(text) == str, 'input needs to be a string!'
        self.str2char = list(text)
        return self.str2char
    
    
    def _chars2nums(self, characters):
        '''converts individual characters to integers.'''
        assert type(characters) == list, 'input needs to be a list of characters!'
        codebook = {'a':0, 'b':1, 'c':2, 'd':3, 'e':4, 'f':5, 'g':6, 'h':7, 'i':8, 'j':9,
               'k':10, 'l':11, 'm':12, 'n':13, 'o':14, 'p':15, 'q':16, 'r':17, 's':18,
               't':19, 'u':20, 'v':21, 'w':22, 'x':23, 'y':24, 'z':25}
        for i, char in enumerate(characters):
            try:
                characters[i] = codebook[char]
            except:
                pass
        self.char2num = characters
        return self.char2num
    
    
    def _nums2chars(self, numbers):
        '''converts individual integers to characters .'''
        assert type(numbers) == list, 'input needs to be a list of numbers!'
        codebook = {0:'a', 1:'b', 2:'c', 3:'d', 4:'e', 5:'f', 6:'g', 7:'h', 8:'i', 9:'j',
               10:'k', 11:'l', 12:'m', 13:'n', 14:'o', 15:'p', 16:'q', 17:'r', 18:'s',
               19:'t', 20:'u', 21:'v', 22:'w', 23:'x', 24:'y', 25:'z'}
        for i, num in enumerate(numbers):
            try:
                numbers[i] = codebook[num]
            except:
                pass
        self.num2chars = numbers
        return self.num2chars
    
    
    def _preprocessing(self, text):
        ''''''
        clean_text = self._clean_text(text)
        list_of_chars = self._string2characters(clean_text)
        list_of_nums = self._chars2nums(list_of_chars)
        return list_of_nums
    
    def encrypt(self, text, shift=3):
        '''return text that is shifted according to user's input.'''
        import numpy as np
        preprocess = self._preprocessing(text)
        nums_shifted = list((np.array(preprocess) + shift) % 26)
        return ''.join(self._nums2chars(nums_shifted))
        
    def decrypt(self, text, shift=3):
        '''returns text shifted by user-defined shift length.'''
        import numpy as np
        preprocess = self._preprocessing(text)
        nums = self._chars2nums(preprocess)
        num_shift = list((np.array(nums) - shift) % 26)
        return ''.join(self._nums2chars(num_shift))<jupyter_output><empty_output><jupyter_text>---<jupyter_code>cc = CaesarCipher()
# example
cc.encrypt('I hope you cannot read this.', shift=6)<jupyter_output><empty_output><jupyter_text>---<jupyter_code>text = 'the QuIcK brown fox jumps over the lazy dog!'
text
# show one encryption
encrypted = cc.encrypt(text, shift=5)
encrypted
# show all encryption possibilities
for i in range(1,26):
    print(cc.encrypt(text, shift=i))
# show all decryption possibilities
for i in range(1,26):
    print('shift{:2}: {}'.format(i, cc.decrypt(encrypted, shift=i)))
    print('')<jupyter_output>shift 1: xliuymgofvsarjsbnyqtwszivxlipedchsk

shift 2: wkhtxlfneurzqiramxpsvryhuwkhodcbgrj

shift 3: vjgswkemdtqyphqzlworuqxgtvjgncbafqi

shift 4: uifrvjdlcspxogpykvnqtpwfsuifmbazeph

shift 5: thequickbrownfoxjumpsoverthelazydog

shift 6: sgdpthbjaqnvmenwitlornudqsgdkzyxcnf

shift 7: rfcosgaizpmuldmvhsknqmtcprfcjyxwbme

shift 8: qebnrfzhyoltkclugrjmplsboqebixwvald

shift 9: pdamqeygxnksjbktfqilokranpdahwvuzkc

shift10: oczlpdxfwmjriajsephknjqzmoczgvutyjb

shift11: nbykocwevliqhzirdogjmipylnbyfutsxia

shift12: maxjnbvdukhpgyhqcnfilhoxkmaxetsrwhz

shift13: lzwimauctjgofxgpbmehkgnwjlzwdsrqvgy

shift14: kyvhlztbsifnewfoaldgjfmvikyvcrqpufx

shift15: jxugkysarhemdvenzkcfieluhjxubqpotew

shift16: iwtfjxrzqgdlcudmyjbehdktgiwtaponsdv

shift17: hvseiwqypfckbtclxiadgcjsfhvszonmrcu

shift18: gurdhvpxoebjasbkwhzcfbiregurynmlqbt

shift19: ftqcguowndaizrajvgybeahqdftqxmlkpas

shift20: espbftnvmczhyqziufxadzgpcespwlkjozr

shift21: droaesmulbygxpyhtewzcyfobdrovkjinyq

shift22: cqnzdrltkaxfwoxgsdvybxena[...]
{'fraction_non_alphanumeric': 0.10878950094974961, 'fraction_numerical': 0.025902262130892764, 'mean_word_length': 3.341829085457271, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 1}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '359975', 'license': 'MIT', 'n_tokens_mistral': 2149, 'n_tokens_neox': 1994, 'n_words': 574, 'path': 'notebooks/Cryptography/1_Caesar_Shift.ipynb', 'repo_name': 'ashishpatel26/Data_Science_Fundamentals', 'size': '5791'}