Creating a Caeser program: Converting ASCII to characters - python

I'm working on python attempting to make a Caeser Cipher program.
So I've made a GUI platform and have been able to make the cipher part work, but it spits out the message only in ASCII.
When you run my program, it takes the info, you say the amount of letters you want the alphabet to shift by, and then says the message in ASCII, how can i get this part to come out in letters?
I tried storing the for loop into a variable then just adding that variable into a common ascii --> character converter, but that doesn't work.
Here's my code:
def encode(userPhrase):
msg = input('Enter your message: ')
key = eval(input("enter a number"))
finalmsg = msg.upper()
for ch in finalmsg:
print( str( ord(ch)+key ), end=' ')

Change your str to chr:
print( chr( ord(ch)+key ), end=' ')
Per the documentation on chr:
Return the string representing a character whose Unicode code point is the integer i. For example, chr(97) returns the string 'a', while chr(957) returns the string 'ν'. This is the inverse of ord().

You need to allow the letters at the end of the alphabet to wrap around to A,B,C... You can do it with modulo arithmetic (complicated), or see the example below
Use chr instead of str. You pass a parameter userPhrase and you ask to enter a message. Also, I suggest using int instead of eval.
def encode(userPhrase):
msg = input('Enter your message: ')
key = int(input("enter a number"))
finalmsg = msg.upper()
for ch in finalmsg:
new_ch = ord(ch)+key
if new_ch > ord('Z'):
new_ch -= 26
print( chr(new_ch), end=' ')
The last problem you have is for non letters (e.g. spaces, etc.)

Related

python string.split() and loops

disclaimer im new to python
i need to split a string input send if to a function that substitutes a character in the string with a different character (like a substitution cipher) but i just dont know how to go about this
print('Welcome to the encryption protocol for top secret governemt cover ups')
string=input('whats your message?')
def encrypt(string):
alpha = "abcdefghijklmnopqrstuvwyz"
sub_alpha = "pokmenliuytrwqazxcvsdfgbhn"
index=0
while index < len(string):
letter=string[index]
im not really sure what im doing im really bad at python, this has had me stumped for 3 days now ive reviewed my course material and tried videos on youtube im probably just really really dumb
I think the key piece of knowledge you're missing is that strings are iterable. So you can do things like:
for c in "FOO":
print(c)
# prints "F\nO\nO\n"
And you can find the index of a character within a string with str.index. So you can build up your cyphertext like this:
alpha = "abcdefghijklmnopqrstuvwyz "
cypher = "pokmenliuytrw qazxcvsdfgbhn"
plaintext = "some string"
cyphertext = ""
for c in plaintext:
char_index = alpha.index(c)
cyphertext += cypher[char_index]
You can also iterate over things inline - this is called a comprehension. So to transform your string you can do this instead of using the for loop:
cyphertext = "".join(cypher[alpha.index(c)] for c in plaintext)
The example above uses the str.join function to concatenate each character of cyphertext.
Here is a solution that asks the question and then iterates through each letter, finding the index in the alpha key, and replacing it with the sub_alpha key equivalent.
Note this example also checks if it should be lowercase or uppercase.
EDIT: if the input character does not have a valid cipher, it doesn't get altered.
EDIT 2: expanded answer to convert both forwards and backwards.
alpha = "abcdefghijklmnopqrstuvwyz"
sub_alpha = "pokmenliuytrwqazxcvsdfgbhn"
def encrypt(in_char):
is_lower_case = in_char.islower()
index = alpha.find(in_char.lower())
if index < 0:
return in_char
elif is_lower_case:
return sub_alpha[index]
else:
return sub_alpha[index].upper()
def decrypt(in_char):
is_lower_case = in_char.islower()
index = sub_alpha.find(in_char.lower())
if index < 0:
return in_char
elif is_lower_case:
return alpha[index]
else:
return alpha[index].upper()
print('Welcome to the encryption protocol for top secret governemt cover ups')
input_str=input('whats your message? ')
output_str=""
for letter in input_str:
output_str += encrypt(letter)
print("Encrypted: ")
print(output_str)
input_str=""
for letter in output_str:
input_str+= decrypt(letter)
print("Decrypted: ")
print(input_str)

Additional letter printed when I am executing Decode()

So when I encode "hello" in my Encode() function, with a shift of three I get the result "khoor". When I attempt to decode "khoor" using my decode function with a shift of three, I get "hellor". This is strange because an extra letter "r" is returned, despite only decoding 5 letters. This happens with every string I attempt to decode, and I have noticed that the last letter of every string to be encoded is added as an additional letter to the decoded string.
ALPHABET = 'abcdefghijklmnopqrstuvwxyz'
def Menu():
print("Please choose from the following: \n")
print("'e' to encode a string.")
print("'d' to decode a string.")
print("'q' to quit.\n")
choice = input("Please enter one of the letters above.\n")
if choice == "e":
print (Encode())
if choice == "d":
print (Decode())
if choice == "q":
print("The program will now exit.")
quit()
def stringValidation():
while True:
try:
valid = str(input("Enter a string to encode.\n"))
return valid
break
except:
print("Value Error. Enter a string with only letters from the alphabet.")
continue
def shiftValidation():
while True:
try:
valid = int(input("Enter the number of shifts you would like.\n"))
return valid
break
except:
print("Value Error. Please enter an integer.")
def decodeShiftValidation():
while True:
try:
valid = int(input("Enter the key. (Number of shifts used to encrypt the encoded word.)\n"))
return valid
break
except:
print("Value Error. Please enter an integer.")
def Encode():
data = []
string = stringValidation() # asks the user for the string input to be encoded
shift = shiftValidation() # asks the user for the number of shifts
for i in string: # for the letters in string...
if i.strip() and i in ALPHABET: # i.strip removes all default whitespace characters from i (string input by user.)
data.append(ALPHABET[(ALPHABET.index(i) + shift) % 26]) # gets position of the letters from input string in ALPHABET using indexing, and adds the shift to get the new position and new letter.
else:
data.append(i) # if it is a space, simply append it to the data.
output = ''.join(data)
return output
encoded_string= Encode()
print(encoded_string)
def Decode():
data = []
string = input("Please enter the string you wish to decode.\n")
shift = int(input("Enter the key. (Number of shifts used when encoding original word. \n"))
for i in string:
if i.strip() and i in ALPHABET:
data.append(ALPHABET[(ALPHABET.index(i) - shift) % 26])
else:
data.append(i)
output = ''.join(data)
return output
Menu()
An indentation error makes the else of your Decode function a else for the for loop (which is a lesser-known feature of for loop: if no break is encountered, the else executes, adding an extra letter in your case).
That explains why you don't get an error but unexpected behaviour.
More here: Why does python use 'else' after for and while loops?
Aside, a very clumsy way to search in the alphabet is to use index, when you can compute the index directly with characters codes:
data.append(ALPHABET[(ord(i)-ord(ALPHABET[0]) + shift) % 26])
Aside #2: note that decode & encode methods are very similar. Factorize them with the shift as parameter (which is the opposite from one method to the other)
I got errors trying to run your script until I changed all of the input statements to raw_input. But I don't quite understand the logic behind if i.strip() and i in ALPHABET:. Also, you don't have to accumulate letters in a list one at a time and then join them back, when Python lets you append strings directly. In any case, when I simplified your Decode() function to the following, it worked for me:
def Decode():
string = raw_input("Please enter the string you wish to decode.\n").lower().strip()
if string.isalpha():
shift = int(raw_input("Enter the key. (Number of shifts used when encoding original word. \n"))
return ''.join([ ALPHABET[(ALPHABET.index(c) - shift) % 26] for c in string])
I also added in a .lower() and .isalpha() check in case the user uses any capital letters or non-alphabetic strings, but there are other things like this you can add to handle other use cases.

Repeating a word to match the length of a string [duplicate]

This question already has answers here:
Repeat string to certain length
(15 answers)
Closed 5 months ago.
In school we are currently using python to create a Caeser Cipher, and a Keyword Cipher. I need help with certain parts of the Keyword cipher, mainly repeating a word to match the length of a string that has been entered, For example:
Entered String: Hello I am Jacob Key: bye Printed text: byebyebyebyeb
I'm okay at Python, but this is very hard for me. Currently this is as far as I got:
def repeat_to_length(key, Input):
return (key * ((ord(Input)/len(key))+1))[:ord(Input)]
Since It's a string I thought if I used ord It would turn it to a number, but I realised when using the ord command you can only have a single character, as I realised when I repeatedly got this error:
TypeError: ord() expected a character, but string of length 16 found
I found some code that did a keyword cipher, but I am not sure which part does the process I am trying to code:
def createVigenereSquare():
start = ord('a')
end = start + 26
index = start
sq = [''] * 256
for i in range(start, end):
row = [''] * 256
for j in range(start, end):
if index > (end - 1):
index = start
row[j] = chr(index)
index += 1
sq[i] = row
index = i + 1
return sq
def createKey(message, keyword):
n = 0
key = ""
for i in range(0, len(message)):
if n >= len(keyword):
n = 0
key += keyword[n]
n += 1
return key
def createCipherText(message, key):
vsquare = createVigenereSquare()
cipher = ""
for i in range(0, len(key)):
cipher += vsquare[ord(key[i])][ord(message[i])]
return cipher
message = str(input("Please input a message using lowercase letters: "))
keyword = str(input("Please input a single word with lowercase letters: "))
key = createKey(message, keyword)
ciphertext = createCipherText(message, key)
print ("Message: " + message)
print ("Keyword: " + keyword)
print ("Key: " + key)
print ("Ciphertext: " + ciphertext)
As I've said I'm only okay at Python, so I don't really understand all the code in the above code, and I really want to be able to write most of it myself.
This is my code so far:
def getMode():
while True:
print("Enter encrypt, e, decrypt or d")
mode = input('Do you want to encrypt the message or decrypt? ') #changes whether the code encrypts or decrypts message
if mode in 'encrypt e decrypt d ENCRYPT E DECRYPT D'.split(): #defines the various inputs that are valid
return mode
else:
print('Enter either "encrypt" or "e" or "decrypt" or "d".') #restarts this string of code if the input the user enters is invalid
Input = input('Enter your message: ')
key = input('Enter the one word key: ')
def repeat_to_length(key, Input):
return (key * ((ord(Input)/len(key))+1))[:ord(Input)]
encryptedKey = repeat_to_length(key, Input)
print(encryptedKey)
I know I've been pretty long winded but if anyone could provide any information on this topic, like explaining the code for the keyword cipher, or just answering my question, I would appreciate it!
AnimeDeamon
Another possibility is to repeat the key enough times to get a string at least as long as the message, and then just grab as many characters as you need from the beginning:
>>> message='Hello I am Jacob'
>>> key='bye'
>>> times=len(message)//len(key)+1
>>> print((times*key)[:len(message)])
byebyebyebyebyeb
We compute times by dividing the length of the message by the length of the string, but we have to add 1, because any remainder will be dropped. times*key is just key repeated times times. This may be longer than we want, so we just take the first len(message) characters.
A simple one-liner could be
''.join(key[i % len(key)] for i in range(len(message)))
What it does, inside out:
We iterate over the indices of the letters in the string message
For each index, we take the remainder after division with the key length (using the % operator) and get the corresponding letter from the key
A list of these letters is constructed (using list comprehension) and joined together to form a string (the join method of an empty string)
Example:
>>> message = "Hello I am Jacob"
>>> key = "bye"
>>> print ''.join(key[i % len(key)] for i in range(len(message)))
byebyebyebyebyeb

How to Use Python's chr() properly

I'm currently working on this code now..
message = input("Enter ASCII codes: ")
decodedMessage = ""
for item in message.split():
decodedMessage += chr(int(item))
print ("Decoded message:", decodedMessage)
#1st Run:
Enter ASCII codes: 97
Decoded message: a
#2nd Run:
Enter ASCII codes: 9797
Decoded message: ♅
The result I want is: aa which is from 97 and another 97 of ascii codes.
How can this be done?
I want it like this.
ord_username = input("Enter Username:")
letters = str(ord_username)
ordlist=[]
z=""
for letter in letters:
number = ord(letter)
ordlist.append(number)
for i in ordlist:
z += str(i) + ""
print (z)
#1st Run:
Enter Username:a
97
#2nd Run:
Enter Username:ab
9798
You want to interpret your string as being composed of 3-digit strings beginning with a '1' or 2-digit strings that cannot begin with a 1. Because of that, you can move through the string from start to finish, plucking out three characters if the first is a 1 or two characters if it isn't. This just needs a simple method:
def stringsplit(message):
message_split = []
while len(message) > 0:
if message[0] == '1':
message_split.append(message[:3])
message = message[3:]
else:
message_split.append(message[:2])
message = message[2:]
return message_split
Then, replace for item in message.split(): with for item in stringsplit(message):
Caveat: Python 2.7 implementation; your mileage may vary, but it shouldn't.

Modifying a program to Decrypt a message using a past encrypted alphabet on python

I need help in writing the second part to this program, which is almost complete. I finish writing the part in which an alphabet is encrypted, but now I find myself stuck in trying to use the new encryption as a sort of decoder ring, to decrypt a a random scrambled message that someone might input into the program.
So to makes this easier to understand, lets say the encryption part of this program gives you: NHPWJXEYOZMAFUSCIGLVTDBKRQ
Now someone would type some random message encrypted using the new scrambled alphabet. So lets say someone types: VYOL OL FR 1LV LJPGJV FJLLNEJ!
Now the program that I need to write will have to use the scrambled alphabet to decoded the message and print: THIS IS MY 1ST SECRET MESSAGE!
If anyone can help, I'll appreciate it. If it still sounds confusing, just ask. Th program that I have is below:
# ENCODE a secret message
# Scramble the alphabet, read a secret message, encode it, print scrambled
import random
def main():
encryption()
decryption()
def encryption():
encrypt=["*"]*26 # all letters available
print(encrypt)
print("Alphabet: ", end="")
for numbah in range(26):
#converts numbah into a letter
letter = chr(numbah+65) # converts 0-25 --> 'A' = 'Z'
print(letter, end="")
#Reminder: find an empty position for that letter to be placed
notfound = True
while notfound:
possible_position = random.randint(0,25)
if encrypt[possible_position] == "*":
notfound = False
encrypt[possible_position] = letter
print("\nScrambled: " , end="")
for numbah in range(26):
print(encrypt[numbah], end="")
print("\n\n")
msg=input("Now, please type your secret message to encode: ")
print("Your secret message: " + msg)
print("Your message encoded: ", end="")
# reminder non alphabetic characters should 'float thru' unchanged!
for alpha in msg.upper():
if alpha < "A" or alpha > "Z":
print(alpha, end="")
else:
print( encrypt[ ord(alpha) - 65], end="")
print("\n")
def decryption():
scram_alph = input("Input the scrambled alphabet from the early prog: ")
scram_mess = input("Input the scrambled messgae you want decoded: ")
main()
There are functions in the Python standard library that make this task quite easy. Have a look at str.translate() and string.maketrans():
>>> import string
>>> t = string.maketrans("NHPWJXEYOZMAFUSCIGLVTDBKRQ",
string.ascii_uppercase)
>>> "DRSA SA XG 1AD AZCEZD XZAAUJZ!".translate(t)
'THIS IS MY 1ST SECRET MESSAGE!'
You're waaaaaay overcomplicating it. Use the built-in iteration tools that Python gives you.
>>> alphabet = "NHPWJXEYOZMAFUSCIGLVTDBKRQ".lower()
>>> message = "VYOL OL FR 1LV LJPGJV FJLLNEJ!".lower()
>>>
>>> table = dict(zip(alphabet, string.ascii_lowercase))
>>> "".join(table.get(char, char) for char in message)
'this is my 1st secret message!'
Explanation
The line
table = dict(zip(alphabet, string.ascii_lowercase))
makes a dictionary of ciphertext letters to plaintext letters. Why? zip of two strings gives you a list of pairs: (first letter, first letter), (second letter, second letter), etc. Then dict of that makes a dictionary. Then the line
"".join(table.get(char, char) for char in message)
says to look up each character in the message in the dictionary (and if it's not there e.g. it's a space or a ! then don't change it) and glue them back into a string.
By the way, to make a scrambled alphabet all you need to do is
>>> alphabet = list(string.ascii_lowercase)
>>> random.shuffle(alphabet)
>>> alphabet = "".join(alphabet)
>>> alphabet
'emxcqgzvkruisjtlydbhafopnw'

Categories

Resources