How to decode a coded sentence? - python

I'm not quite sure why StackOverflow won't allow me to post my code below, so I attached some links to show what I have tried. After typing out my sentence, it will shift any amount of characters from 1-25 which works just fine. However, I need to add a function which will reverse the encoding, and print the original sentence back out. I am not quite sure why Python is spitting out the decoded sentence, the way it does in the 2nd link. It should have the original sentence. Thanks for your help!
def encode( ch, shift):
lower = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZ'
if ch not in lower:
return ch
newch = chr( ord(ch) + shift )
if newch not in lower:
newshift = ( ord(newch) - ord('z') - 1)
nwech = chr ( ord('a') + newshift )
return newch
def decoded(ch, shift):
lower = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWZ'
if ch not in lower:
return ch
newch = chr( ord(ch) + shift )
if newch not in lower:
newshift = ( ord(newch) - ord('z') - 1)
newch = chr ( ord('a') + newshift)
return newch
def main():
shift = int(input("Enter a number between 1 and 25:"))
sentence = input("Please enter a sentence:")
code = ''
decode = ''
for char in sentence:
code = code + encode (char, shift)
for char in code:
decode = decode + encode (char, shift)
print("Uncoded sentence: " + sentence)
print("Encoded sentence: " + code)
print("Decoded sentence: " + decode)
main()
Enter a number between 1 and 25:3
Please enter a sentence:i need help
Uncoded sentence: i need help
Encoded sentence: l qhhg khos
Decoded sentence: o tkkj nkrv

Your decoded function seems to be the same as your encode function (and you're not calling it in any case). Closer to what you need is:
newch = chr( ord(ch) - shift )
in your decoded function, which you should call in place of encode here:
for char in code:
decode = decode + decoded(char, shift)
But now you have another problem. What happens if your shift sends you off the end of the ord range for your characters?

You don't call the decode method. You call the encode method twice...

Related

Caesar Cypher Issue

Currently learning Python, and working on a Caesar Cypher... I can't seem to figure out why my decryption is spitting out the wrong text; currently it does this...
Plain text: Hello
Distance: 65
Encrypt: *&..0
Decrypt: gckkm
I've looked through other posts, but don't seem to find any that have the same issue with decryption - any help would be appreciated. Thank you!
##ENCYPTION
plainText = input("Enter plain text line: ")
distance = int(input("Enter the distance value: "))
code = ""
for ch in plainText:
ordVal = ord(ch)
cipherVal = ordVal + distance
if cipherVal > 127 :
cipherVal = distance - (127 - ordVal | 1)
code += chr(cipherVal)
print(code)
##DECRYPTION
code = input("Enter the coded text: ")
distance = int(input("Enter the distance value: "))
plainText = ""
for ch in code:
ordVal = ord(ch)
cipherVal = ordVal - distance
if cipherVal < 0 :
cipherVal = 127 - (distance - (ordVal - 1))
plainText += chr(cipherVal)
print(plainText)```
I have debugged the code you posted.
lets take for example the input 'm' and distance 20.
the code will be 1 and in the ascii table this means 'SOH' - start of heading.
when trying to copy the output text in the Console and paste it, it didn't know that kind of input.
therefor, you should separate the encryption progress of numbers and letters, and make sure to make a difference between upper case and lower case.
here is the ascii table:
https://www.alpharithms.com/ascii-table-512119/
the reason for separating is to avoid non-input ascii codes.
if you want to include other signs like '-', '_', etc.
than you could ignore all 'cipherVals' between 0 to 31, or it will cause input problems as described above.
Do not worry about space and DEL, I checked and they do work in your code.
There is a major flaw in your algorithm.
Assuming your cipherMessage will be printed on paper, you will have a problem with every cipherVal between 0 and 32 because these are non-printable characters (AKA control codes).
If they do not appear on paper, how will your correspondent will be able to enter them in decrypter?
Caesar was using a 26 character set while you are using a 127 character set (32 of them being non-printable).
You can use your algorithm if you reduce your character set by excluding non-printable characters (first 32 characters plus DEL).
fcis = 32 # First Character In character Set
lcis = 126 # Last Character In character Set
scs = lcis - fcis + 1 # Size of Character Set
# TODO: REPLACE THE FOLLOWING 2 LINES WITH INPUT()
distance = 20
plainText = "Caesar Cypher Issue"
code = ""
for ch in plainText:
val = (ord(ch) - fcis + distance) % scs
code += chr( val + fcis)
print( "plainText:", plainText)
print( "codedText:", code)
#Decrypt
fcis = 32 # First Character In character Set
lcis = 126 # Last Character In character Set
scs = lcis - fcis + 1 # Size of Character Set
# TODO: ADD 2 INPUT STATEMENTS
plainText = ""
for ch in code:
val = (ord( ch) - fcis - distance + scs) % scs
plainText += chr( val + fcis)
print( "codedText:", code)
print( "plainText:", plainText)
Results:
plainText: Caesar Cypher Issue
codedText: Wuy(u'4W.%|y'4]((*y
codedText: Wuy(u'4W.%|y'4]((*y
plainText: Caesar Cypher Issue
You can even define your own custom character set, this way:
cset = " AaBbCcDdEeFfGgHh987654321"
scs = len( cset)
distance = 20
plainText = "Bach 6"
code = ""
for ch in plainText:
val = cset.find(ch)
if val<0:
print( "Unacceptabler character")
break
code += cset[ (val + distance) % scs]
print( "plainText:", plainText)
print( "codedText:", code)
# Decrypt
plaintext = ""
for ch in code:
plaintext += cset[ (cset.find( ch) - distance + scs) % scs]
print( "plainText:", plainText)
Results:
plainText: Bach 6
codedText: 34 e6g
plainText: Bach 6
Be sure your custom character set only use ASCII characters.
Unicode characters (and emojis) will not work with this algorithm.

When writing the Caeser Cipher exercise, the input Secret Message should be outputted as Vhfuhw Phvvdjh but it is outputting as VhfuhwqPhvvdjh instead

My current code is looking like this:
message = input("Message to be encrypted: ")
shift = int(input("Number to shift by: "))
def encrypt(message,shift):
encryption = ""
for i in range(len(message)):
char = message[i]
if (char.isupper()):
encryption += chr((ord(char) + shift-65) % 26 + 65)
else:
encryption += chr((ord(char) + shift - 97) % 26 + 97)
return encryption
print("Encrypted Text:",encrypt(message,shift))
And I am not too sure on my whitespace character is coming out as q instead of a normal " " in a string. This is my first few weeks of coding so I apologize if I have overlooked a simple mistake.
To get the expected result, you should add this conditional before the others:
if char == " ":
encryption += " "
continue
You are not getting the desired output because when you got a space in the input string and passes to the char variable, the space is not a upper letter so your code goes right in the else statement. Although it works for letters it won't work for other special characters. So, as described in the title of your question, if you wish to maintain the space between the words, you simply add the space in your encrypted sentence.
However, my first suggestion will work only for the spaces. If you wish to mantain other special characters (i.e. %, $, #, *, etc) you should use:
if char.isalnum() == False:
encryption += char
continue

Caesar cipher encrypt. Some issues with not properly shifting the characters

Hey so i'm trying to encrypt a string, with a shift key. It works perfectly, the only issue i have is with shifting the characters. For example hello, world!0 and the shift will be 5. I want it to return as olssv, dvysk!0 Basically, only the alphabets will get encrypted. The puncutations & numbers, etc won't be shifted.
keymax = 26
def text():
print('What message(s) are you trying to encrypt?')
return input()
def shift():
key = 0;
while True:
print('Enter the key number (1-%s)' % (keymax))
key = int(input())
if (key >= 1 and key <= keymax):
return key
def encrypt(string, shift):
hidden = ''
for char in string:
if char == ' ':
hidden = hidden + char
elif char.isupper():
hidden = hidden + chr((ord(char) + shift - 65) % 26 + 65)
else:
hidden = hidden + chr((ord(char) + shift - 97) % 26 + 97)
return hidden
text = text()
s = shift()
print("original string: ", text)
print("after encryption: ", encrypt(text, s))
I am fairly new to python, sorry for my bad understandings. Any help would gladly be appreciated!
You could replace the first if statement in your encrypt function with if char.isalpha() == False:. So when the character is not an alphabetical character, the charcter doesn't get changed.
Edit: Also to suggest an improvement, if you want to you can even have shifts upwards of 26. If you use key = key % 26 (%, called modulo, is the remainder of the division, in this case key divided by 26).
This allows you to have keys that are more than 26. This doesn't really change much at all, I just personally like it more

Implementing the Ceaser Cipher function through input in Python

Im trying to create a Ceaser Cipher function in Python that shifts letters based off the input you put in.
plainText = input("Secret message: ")
shift = int(input("Shift: "))
def caesar(plainText, shift):
cipherText = ""
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
cipherText += finalLetter
print(cipherText)
return cipherText
caesar(plainText, shift)
For example, if I put "THE IDES OF MARCH" as my message and put 1 as my shift, it outputs "UIFJEFTPGNBSDI" when it is meant to output "UIF JEFT PG NBSDI." It doesn't keep the spaces and also shifts things like exclamation marks back also when it should leave them as is. Letters should also wrap meaning if I put shift as 3, an X should go back to A.
To fix the spacing issue, you can add an else to if ch.isalpha() and just append the plain text character to the cipher text. This will also handle punctuation and other special, non-alpha characters.
To handle wrapping (e.g. X to A), you'll want to use the modulo operator %. Because A is the 65th ASCII character and not the 0th, you'll need to zero-base the alpha characters, then apply the mod, then add back the offset of 'A'. To shift with wrap-around, you can do something like: final_letter = chr((ord(ch) + shift - ord('A')) % 26 + ord('A')). Note the 26 comes from number of letters in the Latin alphabet.
With these in mind, here is a full example:
plain_text = input("Secret message: ")
shift = int(input("Shift: "))
def caesar(plain_text, shift):
cipher_text = ""
for ch in plain_text:
if ch.isalpha():
final_letter = chr((ord(ch) + shift - ord('A')) % 26 + ord('A'))
cipher_text += final_letter
else:
cipher_text += ch
print(cipher_text)
return cipher_text
caesar(plain_text, shift)
Sample input:
plain_text = "THE IDES OF MARCH"
shift = 1
cipher_text = caesar(plain_text, shift)
print(cipher_text)
# UIF JEFT PG NBSDI
The reason the cipher does not produce the expected result is your code does not account for the case where it is not a alpha non numerical letter. So, a potential fix is just adding handling for spaces.
Code
plainText = input("Secret message: ")
shift = int(input("Shift: "))
def caesar(plainText, shift):
cipherText = ""
for ch in plainText:
if ch.isalpha():
stayInAlphabet = ord(ch) + shift
if stayInAlphabet > ord('z'):
stayInAlphabet -= 26
finalLetter = chr(stayInAlphabet)
cipherText += finalLetter
elif ch is " ":
cipherText += " "
print(cipherText)
return cipherText
caesar(plainText, shift)
Example
Secret message: THE IDES OF MARCH
Shift: 1
UIF JEFT PG NBSDI

Python Vigenere Cipher with required functions

I am working on an online course that has us creating a caesar cipher and vigenere cipher, but we first created two functions; one to find the position of a letter in an alphabet variable, and one to rotate one given character a given amount of times (I have seen that ord() and chr() work better, but the assignment wants us to focus on simpler concepts for now, I guess).
I was able to get the caesar function working, but am unsure as how to go forward with the vigenere cipher. I have watched many videos and looked around this site, but have not found any that allow for the preservation of spaces and non alphabetical characters. Can anyone point me in the right direction of how to start the vigenere function?
#Create function alphabet_position(letter) to turn letter into number
#such as a=0 or e=4, using lowercase to make sure case doesnt matter.
def alphabet_position(letter):
alphabet ="abcdefghijklmnopqrstuvwxyz" #Lists alphabet for a key
lower_letter = letter.lower() #Makes any input lowercase.
return alphabet.index(lower_letter) #Returns the position of input as a number.
def rotate_character(char, rot):
alphabet = "abcdefghijklmnopqrstuvwxyz"
if char.isalpha():
a = alphabet_position(char)
a = (a + rot) % 26 #needs modulo
a = (alphabet[a])
if char.isupper():
a = a.title()
return a
else:
return char
def encrypt(text, rot):
list1 = ""
for char in text:
list1 += rotate_character(char, rot)
return list1
def main():
x = input("Type a message: ")
y = input("Rotate by: ")
#result = rotate_character(x, y) #Not needed once encrypt function works.
result = encrypt(x, y)
print (result)
if __name__ == '__main__':
main()
following my comments; using all printables as alphabet:
from string import ascii_letters, digits, punctuation, whitespace
ALPHABET = ascii_letters + digits
STATIC_ALPHABET = punctuation + whitespace
# minor speedup
ALPHA_INDEX = {a: i for i, a in enumerate(ALPHABET)}
STATIC_ALPHABET_SET = set(STATIC_ALPHABET)
MOD = len(ALPHABET)
def encrypt(char, key):
if char in STATIC_ALPHABET_SET:
return char
else:
return ALPHABET[(ALPHA_INDEX[char] + key) % MOD]
def decrypt(char, key):
if char in STATIC_ALPHABET_SET:
return char
else:
return ALPHABET[(ALPHA_INDEX[char] + MOD - key) % MOD]
key = 17
plain = 'Hello World!'
enc = ''.join(encrypt(char, key) for char in plain)
print(enc) # YvCCF dFICu!
dec = ''.join(decrypt(char, key) for char in enc)
print(dec) # Hello World!

Categories