I was supposed to create strings in my python function to show that the encryption and decryption of my code was working properly. Below is my code.
def encrypt1():
plain1 = input('Enter plain text message: ')
cipher = ''
for each in plain1:
c = (ord(each)+3) % 126
if c < 32:
c+=31
cipher += chr(c)
print ("Your encrypted message is:" + cipher)
encrypt1()
1.) I get the "Inconsistent use of tabs and spaces" error
2.) How should I input set, constant strings to get the wanted input check if my code works (for example, type in meet and get the correct input, etc)
Your code is mostly fine but there are a few issues that I've pointed out:
Your indenting is off. The line cipher += chr(c) should be indented to match the things in the for loop
The function encypt1() shouldn't take a parameter; you are setting plain1 in the method itself so you can declare it there
If you want to deal with just lowercase letters, you should be doing % 123 (value of 'z') and the if clause should check if c < 97. If you want to wrap around printable ascii what you're doing is fine.
This gives:
def encrypt1():
plain1 = input('Enter plain text message: ')
cipher = ''
for each in plain1:
c = (ord(each)+3) % 126
if c < 32:
c+=31
cipher += chr(c)
print ("Your encrypted message is:" + cipher)
Because you want to be able to test this on multiple strings, you would want to pass plain1 as a parameter to the function. But you also want the user to be able to input plain1 if a parameter isn't passed in to the function. For that I would suggest a default parameter. Look at the commented code below:
def encrypt1(plain1=""): # if no argument is passed in, plain1 will be ""
if not plain1: # check if plain1 == "" and if so, read input from user
plain1 = input('Enter plain text message: ')
cipher = ''
for each in plain1:
c = (ord(each)+3) % 126
if c < 32:
c+=31
cipher += chr(c)
return cipher # rather than printing the string, return it instead
So to test this you could do:
test_strings = ['hello world', 'harambe', 'Name', 'InputString']
for phrase in test_strings:
print ("Your encrypted message is:" + encrypt1(phrase))
Which gives the output:
Your encrypted message is:khoor#zruog
Your encrypted message is:kdudpeh
Your encrypted message is:Qdph
Your encrypted message is:LqsxwVwulqj
Related
I am working on an assignment for an introductory Python class and the objective is to prompt the user for a password, determine it fits the given criteria, then encrypt the password by converting the characters to decimal, incrementing the letters and numbers, and decrementing the characters "!##$" then return the new encrypted password. EX. an input of "123ABCabc$" should output "234BCDbcd#" **EDIT -> fixed this output per #gimix
I have everything up to the step of incrementing/decrementing and this last step has me pulling my hair out. I have tried a gang of different things but the two closest to successful attempts I have are as follows.
-in the first sample new_input is the users original input
-in the second sample use_ascii is new_input converted to decimal
1)
def encrypt(new_input):
encrypted = ''
for char in new_input:
if chr(ord(char)) in list(range(97,123)): #ive tried different formatting options, thus the inconsistency
encrypted += chr(ord(char) + 1)
if chr(ord(char)) > str(64):
encrypted += chr(ord(char) + 1)
if chr(ord(char)) >= str(48):
encrypted += chr(ord(char) + 1)
if chr(ord(char)) == str(64):
encrypted += chr(ord(char) - 1)
if chr(ord(char)) >= str(32):
encrypted += chr(ord(char) - 1)
return encrypted
def encrypt(use_ascii):
encr = ''
list1 = list(range(97,123))
list2 = list(range(48,58))
list3 = list(range(56,91))
list4 = list(range(30,35))
for i in use_ascii:
if i in list1:
encr = i + 1
if i in list2:
encr = i + 1
if i in list3:
use_ascii = i + 1
if i in list4:
use_ascii = i - 1
return encr
then my main statements are (swapping 'use_ascii' for 'new_pass' when i test different options)...
new_input = input('Please input a password: \n')
new_encr = encrypt(use_ascii)
print('Your encrypted password is: {}'.format(encrypt(use_ascii)))
**EDIT per Jasmijn
Sample 1 outputs: just errors and I havn't been trying to fix it as much as I suspect that is the less-correct way to proceed
Sample 2 outputs: Your encrypted password is: 100
This is dec for the letter 'd' which suggests it is selecting the last character which fits the criteria of the first 'if' statement and incrementing it. I need it to increment each character and output the new decimal based on the ranges provided.
The easiest way is to use the isalnum() string method to distinguish between letters/numbers an special characters. So you could simply do:
def encrypt(instring):
outstring = ''
for ch in instring:
outstring += chr(ord(ch)+1) if ch.isalnum() else chr(ord(ch)-1)
return outstring
Or, if you want a one-liner:
def encrypt(instring):
return ''.join((chr(ord(ch)+1) if ch.isalnum() else chr(ord(ch)-1) for ch in instring))
The following Caesar Cypher code is not working (Python 3). The text file is being written, but with incorrect cipher.
e.g. Input text as 'Hello' should be written as 'Uryyb!' with a key of 13. Instead it is being written as 'b'
# Caesar cypher function
def rot(text, key):
# Iterate through each character in the message.
for char in text:
# Set cypher_text to an empty string to add to later
cypher_text = ''
# Check if the character is a letter (A-Z/a-z).
if char.isalpha():
# Get the Unicode number from of the character.
num = ord(char)
# If the final number is greater than 'z'/122..
if (num + key) > 122:
# If we go too far, work out how many spaces passed
# 'a'/97 it should be using the proper key.
x = (num + key) - 122
# Add the chr version of x more characters passed
# 'a'/97, take 1 to account for the 'a' position.
# This adds a string character on to the cypher_text
# variable.
cypher_text += chr(x + ord('a') - 1)
# If the rotated value doesn't go passed 'z'/122
elif ((num + key <= 122)):
# Use the key to add to the decimal version of the
# character, add the chr version of the value to the
# cypher text.
cypher_text += chr(num + key)
# Else, if the chracter is not a letter, simply add it as is.
# This way we don't change symbols or spaces.
else:
cypher_text += char
# Return the final result of the processed characters for use.
return cypher_text
# Ask the user for their message
plain_input = input('Input the text you want to encode: ')
# Aks the user for the rotation key
rot_key = int(input('Input the key you want to use from 0 to 25: '))
# Secret message is the result of the rot function
secret_message = rot(plain_input, rot_key)
# Print out message for feedback
print('Writing the following cypher text to file:', secret_message)
# Write the message to file
with open('TestFile.txt', 'a+') as file:
file.write(secret_message)
I'm a beginner in coding and in Python too. Right now I'm working on a Vigenère cipher.
I've gotten far enough to encrypt the message using a key. I added comments on each section of code for reference. Here is my code. My question is below the code.
# Ask user for message
print('type a message.')
message = input()
# print a white line for neatness
print()
# ask user for a key
print('give your key')
key = input()
# create a range with the length of the message
ran = range(len(message))
# Iterate though the range and therefor show all the letters
for i in ran:
# get current letters for this iteration
currentLetter = message[i]
currentKeyLetter = key[i % len(key)]
# Get corresponding numbers
numberLetter = ord(currentLetter)
numberKeyLetter = ord(currentKeyLetter)
# Add two letters
sumTwoLetters = numberLetter + numberKeyLetter
# Get the number of the encrypted letter
newNumberLetter = sumTwoLetters % 128
# Get the encrypted number based on number
newLetter = chr(newNumberLetter)
# print out the result
printText = currentLetter + "(" + str(numberLetter) + ") + "
printText += currentKeyLetter + "(" + str(numberKeyLetter) + ") = "
printText += newLetter + "(" + str(newNumberLetter) + ")"
print(printText)
The code asks for the user's input for the message and key. The ran variable creates a range with the length of the message.
After that, the for loop encrypts the message with the key using ord and chr
The encrypted letter is stored in the variable newLetter
the user can see what the program has done with printText
However, my question is: How can I make the encrypted text appear on a single string. I tried to do it in a loop. I failed miserably (so much so that I don't want to show it)
Does anyone have any suggestions on how to make the encrypted message appear in a single line of text?
You can gather the results in a list and then join() them all into a single string at the end after the for loop. See the comments for the changes.
...
results = [] # ADDED.
# Iterate though the range and therefor show all the letters
for i in ran:
# get current letters for this iteration
currentLetter = message[i]
currentKeyLetter = key[i % len(key)]
# Get corresponding numbers
numberLetter = ord(currentLetter)
numberKeyLetter = ord(currentKeyLetter)
# Add two letters
sumTwoLetters = numberLetter + numberKeyLetter
# Get the number of the encrypted letter
newNumberLetter = sumTwoLetters % 128
# Get the encrypted number based on number
newLetter = chr(newNumberLetter)
# print out the result
printText = currentLetter + "(" + str(numberLetter) + ") + "
printText += currentKeyLetter + "(" + str(numberKeyLetter) + ") = "
printText += newLetter + "(" + str(newNumberLetter) + ")"
results.append(printText) # PUT IN results LIST INSTEAD OF PRINTING.
print(''.join(results)) # ADDED.
There are two easy ways. Either (1) build the string inside the loop and print it outside the loop, or (2) print each character as you move through the loop but without newlines, plus one newline after the loop.
Try one of those approaches and if you need more help, add a comment. You'll learn more by trying it yourself!
After much frustration, I have made my first Caesar Decoder :)
But the problem now is to make the program circular...
For example if we want to shift doge by 1, no problem, it's ephf...
But what about xyz, and the shift was 4???
So programming pros help a first time novice aka newb out :P
Thanks...
import string
def main():
inString = raw_input("Please enter the word to be "
"translated: ")
key = int(raw_input("What is the key value? "))
toConv = [ord(i) for i in inString] #now want to shift it by key
toConv = [x+key for x in toConv]
#^can use map(lambda x:x+key, toConv)
result = ''.join(chr(i) for i in toConv)
print "This is the final result due to the shift", result
Here is Python code that I wrote to be easy to understand. Also, I think the classic Caesar cipher didn't define what to do with punctuation; I think the classic secret messages were unpunctuated and only contained letters. I wrote this to only handle the classic Roman alphabet and pass any other characters unchanged.
As a bonus, you can use this code with a shift of 13 to decode ROT13-encoded jokes.
def caesar_ch(ch, shift):
"""
Caesar cipher for one character. Only shifts 'a' through 'z'
and 'A' through 'Z'; leaves other chars unchanged.
"""
n = ord(ch)
if ord('a') <= n <= ord('z'):
n = n - ord('a')
n = (n + shift) % 26
n = n + ord('a')
return chr(n)
elif ord('A') <= n <= ord('Z'):
n = n - ord('A')
n = (n + shift) % 26
n = n + ord('A')
return chr(n)
else:
return ch
def caesar(s, shift):
"""
Caesar cipher for a string. Only shifts 'a' through 'z'
and 'A' through 'Z'; leaves other chars unchanged.
"""
return ''.join(caesar_ch(ch, shift) for ch in s)
if __name__ == "__main__":
assert caesar("doge", 1) == "ephf"
assert caesar("xyz", 4) == "bcd"
assert caesar("Veni, vidi, vici.", 13) == "Irav, ivqv, ivpv."
The part at the end is a "self-test" for the code. If you run this as a stand-alone program, it will test itself, and "assert" if a test fails.
If you have any questions about this code, just ask and I'll explain.
Just add the key to all the actual character codes, then if the added value is greater than z, modulo with character code of z and add it with the character code of a.
inString, key = "xyz", 4
toConv = [(ord(i) + key) for i in inString] #now want to shift it by key
toConv = [(x % ord("z")) + ord("a") if x > ord("z") else x for x in toConv]
result = ''.join(chr(i) for i in toConv)
print result # cde
I'd recommend using string.translate().
So, we can do the following:
key = 1
table = string.maketrans(string.ascii_lowercase + string.ascii_uppercase, string.ascii_lowercase[key:] + string.ascii_lowercase[:key] + string.ascii_uppercase[key:] + string.ascii_uppercase[:key])
And then we can use it as follows:
'doge'.translate(table) # Outputs 'ephf'
'Doge'.translate(table) # Outputs 'Ephf'
'xyz'.translate(table) # Outputs 'yza'
In particular, this doesn't change characters that are not ascii lowercase or uppercase characters, like numbers or spaces.
'3 2 1 a'.translate(table) # Outputs '3 2 1 b'
in general, to make something "wrap" you use the modulo function (% in Python) with the number you want to wrap, and the range you want it to wrap in. For example, if I wanted to print the numbers 1 through 10 a bajillion times, I would do:
i = 0
while 1:
print(i%10+1)
# I want to see 1-10, and i=10 will give me 0 (10%10==0), so i%10+1!
i += 1
In this case it's a little more difficult because you're using ord, which doesn't have a nice happy "range" of values. If you had done something like string.ascii_lowercase you could do...
import string
codex = string.ascii_lowercase
inString = "abcdxyz"
key = 3
outString = [codex[(codex.index(char)+key)%len(codex)] for char in inString]
However since you're using ord, we're kind of going from ord('A') == 65 to ord('z')==122, so a range of 0 -> 57 (e.g. range(58), with a constant of 65. In other words:
codex = "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz"
# every char for chr(65) -> chr(122)
codex = ''.join([chr(i+65) for i in range(58)]) # this is the same thing!
we can do this instead, but it WILL include the characters [\]^_`
inString, key = 'abcxyzABCXYZ', 4
toConv = [(ord(i)+key-65)%58 for i in inString]
result = ''.join(chr(i+65) for i in toConv)
print(result)
# "efgBCDEFG\\]^"
I know this is kind of an old topic, but I just happened to be working on it today. I found the answers in this thread useful, but they all seemed to use a decision to loop. I figured a way to accomplish the same goal just using the modulus(remainder) operator (%). This allows the number to stay within the range of a table and loop around. It also allows for easy decoding.
# advCeaser.py
# This program uses a ceaser cypher to encode and decode messages
import string
def main():
# Create a table to reference all upper, lower case, numbers and common punctuation.
table = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz1234567890,.!?-#'
print 'This program accepts a message and a key to encode the message.'
print 'If the encoded message is entered with the negative value of the key'
print 'The message will be decoded!'
# Create accumulator to collect coded message
code =''
# Get input from user: Message and encode key
message = raw_input('Enter the message you would like to have encoded:')
key = input('Enter the encode or decode key: ')
# Loop through each character in the message
for ch in message:
# Find the index of the char in the table add the key value
# Then use the remainder function to stay within range of the table.
index = ((table.find(ch)+key)%len(table))
# Add a new character to the code using the index
code = code + table[index]
# Print out the final code
print code
main()
The encode and decode output look like this.
encode:
This program accepts a message and a key to encode the message.
If the encoded message is entered with the negative value of the key
The message will be decoded!
Enter the message you would like to have encoded:The zephyr blows from the east to the west!
Enter the encode or decode key: 10
croj0ozr92jlvy73jp2ywj4rojok34j4yj4roj7o34G
decode:
This program accepts a message and a key to encode the message.
If the encoded message is entered with the negative value of the key
The message will be decoded!
Enter the message you would like to have encoded:croj0ozr92jlvy73jp2ywj4rojok34j4yj4roj7o34G
Enter the encode or decode key: -10
The zephyr blows from the east to the west!
Sorry if my formatting looks catywompus I literally found stackoverflow yesterday! Yes, I literally mean literally :)
This is my assignment:
Write a program which DECRYPTS secret messages.
It should first prompt the user for the scrambled alphabet. It then should ask for the secret message. Finally, it outputs the unscrambled version.
Note that there are exactly 26 characters input for the scrambled alphabet. All alphabetic characters are translated into their decoded equivalents (which will take a WHILE loop), and all other, non-alphabetic characters should be output exactly as they were without translation.
This is my code so far:
decrypt = ["*"] * 26
scram_alphabet = input("Please input the scrambled alphabet in order: ")
while len(scram_alphabet) != 26:
scram_alphabet = input("Please input the scrambled alphabet in order. The alphabet must have 26 characters: ")
num = 0
for each_letter in scram_alphabet:
decrypt[num] = ord(each_letter)
num = num + 1
print()
print("Your scrambled alphabet is: ", end = "")
for num in range (26):
print(chr(decrypt[num]), end = "")
print()
print()
msg = input("Now input your scrambled message: ")
print()
print()
alphabet = 65
for s in range (26):
decrypt[s] = (alphabet)
alphabet = alphabet + 1
print("The unscrambled alphabet is: ", end = "")
for num in range (26):
print(chr(decrypt[num]), end = "")
print()
print()
print("Your unscrambled message reads: ")
for alpha in msg.upper():
if alpha < "A" or alpha > "Z":
print(alpha, end="")
else:
ord_alpha = ord(alpha)
print (chr(decrypt[ord_alpha - 65]), end = "")
Ex: Scrambled Alphabet = XQHAJDENKLTCBZGUYFWVMIPSOR , Scrambled Message = VNKW KW BO 1WV WJHFJV BJWWXEJ!
Everything works fine until I get to the last print statement, where it says that the unscrambled message is the same as the scrambled message. I know that the instructions call for a while loop but I couldn't figure out how to use one to decode the alphabet.
Any helpers?
Well, as has already been noted, you are clobbering your decrypt variable.
However, you are also not building the mapping from the 'scrambled' alphabet to the regular one properly / at all.
Decrypting without using anything more than basic iteration over lists and simple list functions (index()) might look something like this:
cleartext = ""
for c in msg:
if c in alphabet:
pos = alphabet.index(c)
cleartext += string.ascii_uppercase[pos]
else:
cleartext += c
Rather than just patching your code, it could benefit from some improvement. I gather this is probably homework and you are probably not expected to go this far, but IMO there is nothing wrong with learning it anyway.
You are not checking that the input alphabet only contains whatever you consider to be legal values (e.g. probably A-Z in this case), nor are you checking for duplicates. The user could input any old rubbish and break your program otherwise.
Your printing and looping is not very idiomatic.
Functions are good for breaking up your code into more easily readable and maintainable pieces.
This may come across as old school or pedantic, but lines longer than 80 characters are not recommended style for Python. Adjacent string literals (e.g "one""two") will be joined (even across newlines).
If I had to do what you're doing without translate (see below), I might do something like this (just a quick example, could probably be improved with a bit of work):
import string
def validate(alpha):
# Is it exactly 26 characters long?
if len(alpha) != 26: return False
for c in alpha:
# Is every character in [A-Z]?
if c not in string.ascii_uppercase: return False
# Is this character duplicated?
if alpha.count(c) > 1: return False
return True
alphabet = ""
while not validate(alphabet):
alphabet = input("Please input the encryption alphabet in order (only A-Z"
" allowed, with no duplicates): ")
msg = input("Now input your encrypted message: ")
print("Your encrypted alphabet is:", alphabet)
print("Your encrypted message is:", msg)
# Create a mapping from one alphabet to the other using a dictionary
table = dict(zip(alphabet, string.ascii_uppercase))
cleartext = "".join([table[c] if c in table else c for c in msg])
print("Your decrypted message reads:", cleartext)
Lastly, you could also do this using Python's builtin string translation, like so:
import string
# read and validate alphabet
# read message
print(str.translate(message, str.maketrans(alphabet, string.ascii_uppercase)))
You are clobbering decrypt after you wrote all the scrambled letters into it:
crypt = ["*"] * 26
for s in range (26):
val = decrypt[s] - 65
crypt[val] = (s + 65)