Python Caesar Cipher - python

I Am Trying To Make A Caesar Cipher In Python. The Code I Have Written Is Trying To Use An Array Then It Will Be Re-Arranged In A Iteration By The Amount Of The Key. I Am A Few Errors So Any Advice On How To Make The Array System Work Is Appreciated. Would This Idea Work Or Should I Give Up On This Method . Thanks
The Errors i Am Getting Are In The Key Subprogram With It Restarting If The Number Does Not =1-26
import sys
Alphbet =["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"
,"u","v",",w","x","y","z"]
def Menu():
print("Welcome To Password Protect Pc Optimizer 3000 Edition!")
print("\n")
print("1.) Encrypt A New Password And Save It")
print("2.) Access An Existing Saved Password ")
print("3.) Just A One Off Encryption ")
print("4.) Quit Password Protect ")
Answer= input("Please Enter An Option Number:")
if Answer=="1":
Key()
elif Answer==2:
Option2()
elif Answer==3:
Option3()
elif Answer==4:
Quit()
else:
Menu()
def Key():
global Key
Key = input("Please Set A Ceaser Cihper Key (1-26)")
Validation =1
if Key ==1:
Validation +=1
Option1()
Removed A Lot Of elif's Here
elif Key ==26:
Validation +=1
Option1()
if Validation ==1:
print("Please Enter A Valid Number")
Key()
def Option1():
Hold=["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18
","19","20","21","22","23","24","25","26"]
for i in range(Key):
Temp= Alphabet[Hold]
Alphabet[Hold]= Alphabet[Hold-1]
Alphabet[Hold-1] =Temp
print(Alphabet)
Menu()'

Here is a simplified version:
from collections import deque
import string
class CaesarCypher(object):
def __init__(self, cypher):
encrypt_rotate = deque(string.ascii_lowercase)
encrypt_rotate.rotate(-cypher)
decrypt_rotate = deque(string.ascii_lowercase)
decrypt_rotate.rotate(cypher)
encrypt_trans = ''.join(encrypt_rotate)
decrypt_trans = ''.join(decrypt_rotate)
self.encrypt_table = str.maketrans(string.ascii_lowercase, encrypt_trans)
self.decrypt_table = str.maketrans(string.ascii_lowercase, decrypt_trans)
def encrypt(self, text):
return text.translate(self.encrypt_table)
def decrypt(self, text):
return text.translate(self.decrypt_table)
First import deque to use its rotate method that will shift the elements position, then import string which contains the alphabet so we don't have to declare it.
Then create a class to encapsulate the encrypt and decrypt methods. Define a __init__ method so the class will take an argument for the cypher and prepare the translation tables that will shift the characters.
Finally add 2 methods to the class to encrypt and decrypt based on the translation table.
Now you can use your class this way:
caesar = CaesarCypher(5)
test = caesar.encrypt('Hello World!')
print(test)
# > 'Hjqqt Wtwqi!'
test2 = caesar.decrypt(test)
print(test2)
# > 'Hello World!'
Edit:
This example only takes care of lowercase letters, if you want to encrypt uppercase you need to declare a separate table for string.ascii_uppercase and translate the text twice on the decrypt and encrypt methods, first for lower then for upper.
Edit2: If you are on python 2.7 the maketrans method is on the string class not in str. Thanks to #t.m.adam for the comment.

Related

Error- encrypt() .... positional argument : `data`

So i been trying to make a encoder and decoder just for fun. Since i am new to python i usually sit and try to debug the code bymyself but seems like this is pretty hard. Would Appreciate some help :).
Error =
ValueError: Fernet key must be 32 url-safe base64-encoded bytes.
from cryptography.fernet import Fernet as dpsisbad
question1 = input("Do You Have A Key? (yes - y and no - n)\n")
if question1 == "y":
key = input("Enter Your Key Here \n")
print(key)
else:
key = dpsisbad.generate_key()
print("Please Keep this Key Safely.\n")
print(key)
dpsstalks = dpsisbad(key)
question2 = input("Do You Want to Encode Or Decode The Message? (Encode = e and Decode = d)\n")
if question2 == "e":
gg = input("Enter the text you want to encode. \n")
encoded_text = gg.encode()
token = dpsstalks.encrypt(encoded_text)
print(token)
else:
text1 = input("Enter the the encrypted text. \n")
token = dpsstalks.decrypt(text1)
print(token)
I've run into a similar problem some time ago. Your code is almost correct, the problem is that you haven't considered the fact that in python the method input() accept only string as input(so when you write b'abcd' in the input it will take the whole String as a String and it will ignore the b'', because it will think that it is part of the string). For this reason both the key and the token must be decoded when you are printing them out and you must encode them in the input() method, the code should look like this:
from cryptography.fernet import Fernet as dpsisbad
question1 = input("Do You Have A Key? (yes - y and no - n)\n")
if question1 == "y":
key = input("Enter Your Key Here \n").encode()
print(key.decode())
else:
key = dpsisbad.generate_key()
print("Please Keep this Key Safely.\n")
print(key.decode())
dpsstalks = dpsisbad(key)
while True:
question2 = input("Do You Want to Encode Or Decode The Message? (Encode = e, Decode = d, quit = q)\n")
if question2 == "e":
gg = input("Enter the text you want to encode. \n")
encoded_text = gg.encode()
token = dpsstalks.encrypt(encoded_text)
print(token.decode())
elif question2 == "d":
text1 = input("Enter the the encrypted text. \n").encode()
token = dpsstalks.decrypt(text1)
print(token.decode())
elif question2 in ("q", "exit", "quit"):
break
The while and the last elif aren't really needed, I just added them to make it easyer to test and don't have to restart the program each time.
Sorry for my poor english, but I'm not native speaker.
If I have not been clear.
Edit:
In the output you could do also a thingh like this:
str(token)[2 : -1]
What it is actually doing it's trasforming the token in a string and removing the first two(b') and the last one character('), but I would not do it since for how much it works it is not the correct way, I am illustrating it to you anyway because maybe it could be useful for you (if only to modify the strings).

Unable to write condition to update dictionary value in python

Please help! How can I write condition in my existing code which will check as below. Please look commented block. I can't append value in the dictionary/list. What do I need to write/change?
When user come back to main menu and run encryption process again using same key file but save the encrypted file in different name. User can create as many encrypted file using same key.
My try:
import Encrypt
from collections import defaultdict
key_value_dict = {}
def encrypt_file():
try:
txtfile = input("Your plain txt file that you want to encrypt : ")
encrypt_file = input("Directory to save the encrypted file : ")
key = input("Key for encryption : ")
# process for encryption
Encrypt.encrypt_file(txtfile, encrypt_file, key)
# ----------------------------------------------------------------
key_value_dict = defaultdict(list, {key: encrypt_file})
print(key_value_dict)
key_value_dict [key].append(encrypt_file)
print(key_value_dict )
# --------------------------------------------------------------------
except FileNotFoundError:
print("File Not Found!")
def menu():
selection = True
while selection:
print("""
MAIN MENU:
[1] Encrypt files using existing keys.
[2] Exit.
""")
try:
selection = input("Please select : ")
if selection == "1":
encrypt_file() # call function
elif selection == "2":
print("\n[4] Keys are used for encryption:", "\n", key_value_dict)
selection = None
else:
print("\n Invalid selection! Try again")
except ValueError:
print("\n Exception: Invalid user input!")
# Main function
if __name__ == '__main__':
menu()
If I understand correctly I don't think you need defaultdict
Try this:
# define this first outside the function like you have
encrypt_key_value_dict = {}
# Within your code block, get rid of the assignment to default dict
if encrypt_key_value_dict[key]:
encrypt_key_value_dict.append(encrypt_file)
else:
encrypt_key_value_dict[key] = [encrypt_file]
I can't see from your code where you keys are getting passed etc but I am sure you can figure that out.

What kind of unittests make sense for a chatbot in python?

I am creating a simple chatbot at the moment and now I would like to test it using the unittests package. I am new to programming and I have only recently heard about the existence of unit tests. I am thinking that for a chatbot to be tested, it would make sense to see if it gives the right output to the right user input. So if the user writes "Hi", for example, it should output "Hey what's up?" as specified in the library (I have written a bunch of libraries for it; it is not a deep-learning-kinda-bot).
This is the code of my chatbot:
# importing regular expression operations, which we need later to access the libraries
import re
import random # later we want to pick a chatbot answer to a statement by random
from Jordan_Library import dict_smalltalk, dict_caring, dict_cursing, dict_meditating, dict_corona # import libraries
# and here we imported all the topic libraries
class JordanBot:
"""
A class that represents the abilities of Jordan the chatbot.
...
Attributes
----------
name : str
user can insert name, which will later be shown in the chat.
Methods
----------
name : str
user can insert name, which will later be shown in the chat.
"""
def __init__(self, name): # this function is always called when a new object of the class is called
"""
Constructing topics for Jordan. Takes the user's name as an argument.
"""
self.name = name
def chat(self):
"""
A function that enables chatting with Jordan after picking a topic.
Take no arguments.
"""
topics = [dict_smalltalk, dict_caring, dict_cursing, dict_meditating, dict_corona]
while True:
print("Welcome. My name is Jordan. You can now choose a topic that we can talk about.")
print("Press '0' to have some good old-fashioned smalltalk.")
print("Press '1' to tell me about your deepest sorrows and your destroyed soul.")
print("Press '2' to curse with me.")
print("Press '3' to meditate with me.")
print("Press '4' to talk about Corona.")
# execute this welcome text and tell user what to press in order to pick a topic.
choice = input(">>> ")
# initialize input
if choice == '0': # determine which key to press to initiate the specific topic
print("Alrighty, let's do some chitchatting.")# initiate welcome text for specific topic
print("Don't forget that I am sensitive to punctuation.")
elif choice == '1':
print("Please tell me about your deepest sorrows and your destroyed soul.")
print("Don't forget that I am sensitive to punctuation.")
elif choice == '2':
print("Make yourself ready. let's insult each other!")
print("Don't forget that I am sensitive to punctuation.")
elif choice == '3':
print("Ok then, let's meditate.")
print("Don't forget that I am sensitive to punctuation..")
elif choice == '4':
print("Let's talk about Corona.")
print("Don't forget that I am sensitive to punctuation..")
elif choice == 'q': # if user wants to quit
break
else: # if user pressed the wrong key.
print("Try again.")
edition = topics[int(choice)]
statement = list(map(lambda x:re.compile(x[0], re.IGNORECASE), edition))
# list(map()) applies a function to all elements of a specified object, in this case the cursing library
# lambda makes sure that re.compile is applied in a certain way to all elements of the library without being case-sensitive
# re.compile makes sure that the elemets are turned into objects that can be matched later to another item in the library
answer = list(map(lambda x:x[1], edition))
# same here, but here we pick the second argument in the list x[1], which entails Jordan's answers
while True:
userInput = input(' ' + self.name + ' >>> ') # this allows for the user to type in keys
resp = "I did not understand what you said. Also, I am sensitive to punctuation." # initalize response variable
counter = 0 # initalize counter
while resp == "I did not understand what you said. Also, I am sensitive to punctuation." and counter < len(statement): # determine when to start my loop
for i in range(0, len(statement)): # loop through the indexed library
match = statement[i].match(userInput) # look if input of the user matches with one of the words in the library
if match:
word = statement[i].split(userInput)[1] # We have to take the first element of this list
resp = random.choice(answer[i]) # if there is a match, pick a random answer from x[1]
counter += 1 # make sure that the counter is now + 1 so it does not write the initialized response from the beginning but continues with the loop
# if there is no match though, then it will write the initialized answer
if userInput == 'q':
print(random.choice(answer[i]))
print("---------------------------------")
print("Do you want to choose another topic? Pick below or press 'q' to quit for realsies.")
print("---------------------------------")
break
resp = resp.format(word)
print('____________')
print(' ')
print('Jordan >>> ' + resp) # print Jordan's answer
The unittests I am trying to create are something like:
import unittest
from Jordan_Library import dict_smalltalk, dict_caring, dict_cursing, dict_meditating, dict_corona # import dictionairies
from Jordan_Class import JordanBot
class testJordan(unittest.TestCase):
"""
A class to test several units of Jordan to make sure everything is working correctly.
"""
def test_match(self):
j = JordanBot('StringName')
j.chat()
user_input = "What are you?"
bot_output = list(map(lambda x:x[1], dict_smalltalk)) # this is how I access the right response in the right library
matched = bot_output.match(user_input)
self.assertIn("I am a chatbot, dude. What do you think?", matched)
def test_regex(self):
j = JordanBot('StringName')
j.chat()
text = 'something'
regex = {}
self.assertRegexpMatches(text, regex)
if __name__ == '__main__':
unittest.main()
The main problem is that these lines only run my code, but not really any unit tests. Advice is much appreciated!

What is the best practice for organizing a piece of reusable code?

I am building a text-based encryption and decryption game. There are different levels, and each level uses a different cipher for encrypting a text. I am trying to figure out the best practice for the series of questions and prompts (the narrative) I give the user to determine if he wants to practice, do the test, encrypt, or decrypt. 90% of the narrative is the same for each level, so I don't want to repeat myself with identical code. What is the best way to do this?
My first thought was to define a function that contained the general script, and to call the specific functions as parameters. (This is what I have attempted to do below). But I seem to run into a scope problem. When I call the caesar() function as one of the arguments in the script() function, I need to enter the text to be encrypted, but this text isn't provided by the user until the script() function has already started running.
Should I be using a class to define the narrative portion of the program, and then inherit to more specific types?
Or should I just repeat the narrative code at the different levels?
Here is the narrative script():
def script(encrypt, decrypt):
"""Asks user if they want to practice (encode or decode) or take the
test, and calls the corresponding function."""
encrypt = encrypt
decrypt = decrypt
while True:
print('Type Q to quit. Type M to return to the main menu.')
prac_test = input('would you like to practice or take the test? P/T')
if prac_test.lower() == 'p':
choice = input('Would you like to encrypt or decrypt? E/D ')
if choice.lower() == 'e':
text = input('Enter the text you would like to encode: ')
encrypt
elif choice.lower() == 'd':
text = input('Enter the text you would like to decode: ')
key = int(input('Enter the key: '))
decrypt
else:
print('You must enter either "E" or "D" to encode or decode a
text. ')
elif prac_test.lower() == 't':
text = random.choice(text_list)
encrypted_text = encrypt
print(encrypted_text[0])
answer = input('s/nCan you decode this string? ')
if answer.lower() == ran_str.lower():
print('Congrats! You solved level 1!\n')
pass
elif answer != ran_str:
print("Sorry, that's not correct. Why don't you practice some
more?\n")
script(encrypt, decrypt)
elif prac_test.lower() == 'q':
exit()
elif prac_test.lower() == 'm':
break
else:
print('Please enter a valid choice.')
Here is one of the levels using a caesar cipher:
def caesar(mode, text, key=None):
"""
...
The dictionaries that convert between letters and numbers are stored in the .helper file, imported above.
"""
mode = mode
if mode == 'encrypt':
key = random.randint(1, 25)
elif mode == 'decrypt':
key = key
str_key = str(key)
text = text.lower()
# converts each letter of the text to a number
num_list = [alph_to_num[s] if s in alph else s for s in text]
if mode == 'encrypt':
# adds key-value to each number
new_list = [num_to_alph[(n + key) % 26] if n in num else n for n in
num_list]
elif mode == 'decrypt':
# subtracts key-value from each number
new_list = [num_to_alph[(n - key) % 26] if n in num else n for n in
num_list]
new_str = ''
for i in new_list:
new_str += i
return new_str, str_key
And here is who I would try to use them together:
script(caesar('encrypt' text), caesar('decrypt', text, key))
Please instruct me on the best way to organize this reusable narrative code.
You probably want to use multiple functions:
One, that we will call main(), to display the menu and interact with the user
A class Caesar, that expose two functions: encrypt(text, key) and decrypt(text, key)
A simple program could then look like
def main():
print("Welcome to the game")
action = input("Would you like to encrypt or decrypt a text [e/d]">).lower()
text = input("What is the text you want to test on ? >")
key = input("What's your key")
# optionnaly, ask for what kind of cipher they want to use, then use a dict to chose the right class
cipher = Caesar()
if action == "e":
output = cipher.encrypt(text, key=key)
else:
output = cipher.decrypt(text, key=key)
print(output)
print("Thanks for playing!")

Caesar Cipher code only Ciphers one letter not entire string

So I'm in the middle of making a simple Caesar cipher for practice and I can't get it to decipher entire strings, just individual letters.
symbol_add is the function in question.
Here's the code:
import re
alphabet = "abcdefghijklmnopqrstuvwxyz"
def cleanIt(clean):
global alphabet
s = re.sub('[^a-z]+', '?', str(clean))
return s
def symbol_add(symbol, key):
encryptedMsg = ""
for x in symbol:
position = alphabet.find(x)
newPosition = (position + key) % 26
newLetter = alphabet[nyPosisjon]
encryptedMsg += nyBokstav
return encryptedMsg
def cipher(data,key):
text = ""
if data in alphabet:
text += symbol_add(symbol=data,key=key)
return text
def main():
try:
msg = (input("Write the message you would like to encrypt\n"))
key = int(input("which key would you like to use?\n"))
cleanIt(clean=msg)
print(cipher(data=msg, key=key))
except ValueError:
print("Write a number!")
main()
I'm sure the solution is pretty simple, still learning.
Any help in how to solve this will be greatly appreciated!
import re
alphabet = "abcdefghijklmnopqrstuvwxyz"
def cleanIt(clean):
global alphabet
s = re.sub('[^a-z]+', '?', str(clean))
return s
def symbol_add(symbol, key):
position = alphabet.find(symbol)
newPosition = (position + key) % 26
newLetter = alphabet[newPosition]
return newLetter
def cipher(data,key):
text = ""
for letter in data:
if letter in alphabet:
text += symbol_add(symbol=letter,key=key)
return text
def main():
try:
msg = (input("Write the message you would like to encrypt\n"))
key = int(input("which key would you like to use?\n"))
# Note: you need to assign msg to be equal to cleanIt(clean=msg).
# Just calling cleanIt(clean=msg) won't work, as strings
# are immutable in Python
msg = cleanIt(clean=msg)
print(cipher(data=msg, key=key))
except ValueError:
print("Write a number!")
main()
The main changes are:
The for loop was moved from symbol_add to cipher, so that symbol_add gets called for each character
In main(): cleanIt(clean=msg) -> msg = cleanIt(clean=msg); the reason for this is that strings are immutable in Python, meaning that you need to reassign the variable msg to essentially point to the new string.
Output of this code:
Write the message you would like to encrypt
test
which key would you like to use?
1
uftu
Also, try to stick to a single naming convention; you have a function that follows camelCase (cleanIt) and another that follows snake_case (symbol_add). Try and name all functions in the same way. (The convention in Python is to use snake_case for functions)
You can streamline your cipher method quite a bit if you fill a dictionary as lookup when entering the method. It contains the mapping based on the key provided and maps your input characters to to the cipher-character.
Its much faster to look up in a dict then to .index() into a string.
Using dict.get(key[,default]) allows to provide the '?' for unknowns so you need no import re and no preprocessing.
Read about dict.get(): Why dict.get(key) instead of dict[key]?
Adding uppercase mapping to the chiffre is trivial as well based on the lower case ones:
alphabet = "abcdefghijklmnopqrstuvwxyz"
def cipher(data, key):
# in case you change alphabet
la = len(alphabet)
# get the default lookup
chiffre = { c:alphabet[(i+key)%la] for i,c in enumerate(alphabet) }
# create lookup for upper cases as well
chiffre.update( { c.upper():n.upper() for c,n in chiffre.items() } )
# supply ? for all unknowns, use the knowns where possible and return as string
return ''.join( (chiffre.get(c,"?") for c in data) )
def main():
try:
msg = (input("Write the message you would like to encrypt\n"))
key = int(input("which key would you like to use?\n"))
print(cipher(data=msg, key=key))
except ValueError:
print("Write a number!")
main()
Output:
Write the message you would like to encrypt
Hello World
which key would you like to use?
1
Ifmmp?Xpsme

Categories