ECX 30 Days of Code and Design
Day 8
Caesar Cipher
A Caesar cipher is an ancient form of encryption. It involves taking a text (a string) as input and encoding it by replacing each letter with the one n-steps next to it in the alphabet. (E.g., shifting "Python" by 5 becomes "Udymts." Note that this "shift" wraps around, which is why "y" becomes "d".)
Task:
- Write a function that takes in as parameters, a plaintext (string) to encode, and a shift value, and outputs the encoded value of the string.
- Write another similar function that takes in the encoded string, with a shift value, and decodes it.
- Finally, write a third function that takes in a text, a shift value, and a third parameter to indicate whether to encode or decode the given text (i.e., f("string", 5, True/False) ), and print out the encoded (or decoded) text accordingly.
My Approach
This is my approach to the task. I will explain it in bits throughout this article.
import string
import sys
# The word to be encoded shifts by 5 to the right, while the word to be decoded shifts by 5 to the left.
shift = 5
print(' Caesar Cipher '.center(40, '*'))
choices = ['e', 'd']
user_choice = input('Do you wish to [e]ncode, [d]ecode, or quit (any other letter)?: ').lower()
if user_choice not in choices:
print('Program closed.')
sys.exit()
word = input('Enter the word: ')
# ENCODING FUNCTION
def encode_words(words, shifts):
"""This encodes a word using Caesar cipher."""
# Variable for storing the encoded word.
encoded_word = ''
for i in words:
# Check for space and tab
if ord(i) == 32 or ord(i) == 9:
shifted_word = ord(i)
# Check for punctuations
elif i in string.punctuation:
shifted_word = ord(i)
# Check if the character is lowercase or uppercase
elif i.islower():
shifted_word = ord(i) + shifts
# Lowercase spans from 97 to 122 (decimal) on the ASCII table
# If the chars exceeds 122, we get the number it uses to exceed it and add to 96 (the character before a)
if shifted_word > 122:
shifted_word = (shifted_word - 122) + 96
else:
shifted_word = ord(i) + shifts
# Uppercase spans from 65 to 90 (decimal) on the ASCII table
# If the chars exceeds 90, we get the number it uses to exceed it and add to 64 (the character before A)
if shifted_word > 90:
shifted_word = (shifted_word - 90) + 64
encoded_word = encoded_word + chr(shifted_word)
print('Word:', word)
print('Encoded word:', encoded_word)
# DECODING FUNCTION
def decode_words(words, shifts):
"""This decodes a word using Caesar cipher"""
# Variable for storing the decoded word.
decoded_word = ''
for i in words:
# Check for space and tab
if ord(i) == 32 or ord(i) == 9:
shifted_word = ord(i)
# Check for punctuations
elif i in string.punctuation:
shifted_word = ord(i)
# Check if the character is lowercase or uppercase
elif i.islower():
shifted_word = ord(i) - shifts
# If the char is less 122, we get difference subtract from 123 (the character after z)
if shifted_word < 97:
shifted_word = (shifted_word - 97) + 123
else:
shifted_word = ord(i) - shifts
# If the char is less 65, we get difference and subtract from 91 (the character after Z)
if shifted_word < 65:
shifted_word = (shifted_word - 65) + 91
decoded_word = decoded_word + chr(shifted_word)
print('Word:', word)
print('Decoded word:', decoded_word)
def encode_decode(words, shifts, choice):
"""This checks if the users want to encode or decode, and calls the required function."""
if choice == 'e':
encode_words(words, shifts)
elif choice == 'd':
decode_words(words, shifts)
encode_decode(word, shift, user_choice)
Encoding or Decoding?
First, we import the string module, which we would use to check if a character is a punctuation mark, and the sys module, which we would use to exit the program if the player does not want to perform any function. We then create the global variables to be used. We create a shifting value, shift, which is made to have the integer value of 5. When we are encoding, we advance the individual characters by 5 on the ASCII table, while when we are decoding, we go 5 steps backwards on the ASCII table. We create a list containing e for encoding and d for decoding. We prompt the user to choose if s/he wants to encode or decode a word (or sentence), or quit the program. If the user chooses either e or d we ask the user to input the word s/he wants to encode/decode, else we quit the program.
import string
import sys
shift = 5
print(' Caesar Cipher '.center(40, '*'))
choices = ['e', 'd']
user_choice = input('Do you wish to [e]ncode, [d]ecode, or quit (any other letter)?: ').lower()
if user_choice not in choices:
print('Program closed.')
sys.exit()
word = input('Enter the word: ')
Encoding function
Next, we create the encoding function, which iterates through the letters in the word(s) to be encoded. First, we check if it is a space (32 on the ASCII table) or a tab (11 on the ASCII table); next, we check if it is a punctuation mark. We would not shift spaces, tabs and punctuation marks. Next, we check if it is lowercase or uppercase. We then convert the character to its integer value, shift it by 5, and save its value in shifted_word. We check if the encoded word is within the range of the values for alphabets on the ASCII table. If it exceeds the value (122 for lowercase and 90 for uppercase), we get the difference and add it to the value before ‘a’ for lowercase (which is 96 on the ASCII table as ‘a’ is 97) or ‘A’ for uppercase (which is 64 on the ASCII table as ‘A’ is 65).
def encode_words(words, shifts):
"""This encodes a word using Caesar cipher."""
encoded_word = ''
for i in words:
if ord(i) == 32 or ord(i) == 9:
shifted_word = ord(i)
elif i in string.punctuation:
shifted_word = ord(i)
elif i.islower():
shifted_word = ord(i) + shifts
if shifted_word > 122:
shifted_word = (shifted_word - 122) + 96
else:
shifted_word = ord(i) + shifts
if shifted_word > 90:
shifted_word = (shifted_word - 90) + 64
encoded_word = encoded_word + chr(shifted_word)
print('Word:', word)
print('Encoded word:', encoded_word)
Decoding Function
Next, we create a function to decode words. It follows a similar pattern as the encoding function, but this time we shift 5 steps backwards on the ASCII table. After checking for spaces, tabs, and punctuation marks, we check for lowercase or uppercase. If the shifted word goes below the values of ‘a’ or ‘A’ (97 and 65 respectively on the ASCII table), we get the negative difference and add to either the value after ‘z’ for lowercase or ‘Z’ for uppercase.
def decode_words(words, shifts):
"""This decodes a word using Caesar cipher"""
decoded_word = ''
for i in words:
if ord(i) == 32 or ord(i) == 9:
shifted_word = ord(i)
elif i in string.punctuation:
shifted_word = ord(i)
elif i.islower():
shifted_word = ord(i) - shifts
if shifted_word < 97:
shifted_word = (shifted_word - 97) + 123
else:
shifted_word = ord(i) - shifts
if shifted_word < 65:
shifted_word = (shifted_word - 65) + 91
decoded_word = decoded_word + chr(shifted_word)
print('Word:', word)
print('Decoded word:', decoded_word)
Main Function
Next is the main function, which accepts three arguments (the word/sentence to encode, the shifting value, and the choice of the user to either encode or decode). If the user chooses e, the encoding function is called, while if he chooses d, the decoding function is called.
def encode_decode(words, shifts, choice):
"""This checks if the users want to encode or decode, and calls the required function."""
if choice == 'e':
encode_words(words, shifts)
elif choice == 'd':
decode_words(words, shifts)
encode_decode(word, shift, user_choice)
Output
Encoding
************ Caesar Cipher *************
Do you wish to [e]ncode, [d]ecode, or quit (any other letter)?: e
Enter the word: Today is the first day of the rest of our lives.
Word: Today is the first day of the rest of our lives.
Encoded word: Ytifd nx ymj knwxy ifd tk ymj wjxy tk tzw qnajx.
Decoding
************ Caesar Cipher *************
Do you wish to [e]ncode, [d]ecode, or quit (any other letter)?: d
Enter the word: Ytifd nx ymj knwxy ifd tk ymj wjxy tk tzw qnajx.
Word: Ytifd nx ymj knwxy ifd tk ymj wjxy tk tzw qnajx.
Decoded word: Today is the first day of the rest of our lives.
Run the code on Replit