I have an assignment for a lab that asks me to decrypt an input file that has been encrypted with a ceasar cipher. As background, my instructor has already let everyone know that the cipher has a shift distance of three.
I was able to get my to write to an output file, but my output.txt is completely unreadable, and not close at all to what the expected output should be. I remember my instructor mentioning that we could use ord() and chr() combined with arithmetic to transform the encoded characters to plaintext.
decode = inpf.readlines()
for line in decode:
output = ""
c = str()
for c in line:
if c >= "a" and c <= "z":
x = ord(c)
x += 23
x %= 26
y = chr(x)
output = output + y
if c >= "A" and c <= "Z":
x = ord(c)
x += 23
x %= 26
y = chr(x)
output = output + y
else:
output = output + c
outf.write(output + "\n")
I appreciate any help or advice you can offer! Thanks!!
EDIT:
Sample Input: "Wkh Orug Ri Wkh Ulqjv:"
Output: " :"
Expected Output: "The Lord Of The Rings:"
The ord() method in Python converts a character into its Unicode code value. Capital 'A' starts from unicode 65 and small 'a' from 97. Also you should use 'elif' instead of second 'if' statement. Otherwise, in case of a small letter, the letter will repeat. You need to get the letters position in alphabet, apply the shift and convert it back to unicode. A working example of your code is given below:
inpf = open("input.txt",'r')
outf = open("output.txt",'w')
decode = inpf.readlines()
for line in decode:
output = ""
c = str()
for c in line:
if c >= "a" and c <= "z":
x = ord(c) - 97 #small a
x -= 3
x = (x+26)%26 #For handling negative numbers
y = chr(x + 97)
output = output + y
elif c >= "A" and c <= "Z":
x = ord(c) - 65 #Capital A
x -= 3
x = (x+26)%26 #For handling negative numbers
y = chr(x + 65)
output = output + y
else:
output = output + c
outf.write(output + "\n")
Related
How do I shift the end of the alphabet so "z" becomes "a"?
i was thinking a if statement
plaintext = input("please type message:")
def split(plaintext):
return list(plaintext)
print(split(plaintext))
for s in plaintext:
a = ord(s)
print (a)
list1=[]
for t in plaintext:
b = ord(t)
c = b+1
print (c)
list1.append(c)
print (list1)
aa =""
for ab in list1:
aa = aa + chr(ab)
print (str(aa))
print(split(aa))
if you just want to increase the character by one you could do this:
def inc_chr(c):
return chr((ord(c) + 1 - ord("a")) % 26 + ord("a"))
test:
for char in "abcxyz":
print(f"{char} {inc_chr(char)}")
outputs:
a b
b c
c d
x y
y z
z a
basically you do calculations modulo 26 with an offset of ord("a") = 97.
You can use a look up dict and convert the characters.
import string
alphabets = string.ascii_lowercase
look_up = {alphabets[i]: alphabets[i-1] for i in range(len(alphabets))}
You can then use this lookup for cypher
test = "This will be encoded"
out = = "".join([look_up.get(char, char) for char in test])
print(out)
This question already has answers here:
Conversion of string to upper case without inbuilt methods
(7 answers)
Closed 4 years ago.
I am writing a code that will encrypt a list of String entered by user. these lists will be encrypted and then it will be decrypted.
But once it will reach the part of encryption it gives me this error.
Traceback (most recent call last): File "C:/Users/dana/Desktop/q2.py", line 16, in
x = ord(c) TypeError: ord() expected a character, but string of length 4 found
I am sure that it will give the same error even in the decryption part.
This is my code:
# Encryption
list1=[]
list2=[]
i = 0
while not(False):
plain_text = input ("Enter any string ")
if (plain_text !='q'):
list1.append(plain_text)
i=i+1
else:
break
encrypted_text = ""
for c in list1:
x = ord(c)
x = x + 1
c2 = chr(x)
encrypted_text = encrypted_text + c2
print(encrypted_text)
#Decryption
encrypted_text = "Uijt!jt!b!uftu/!BCD!bcd"
plain_text = ""
for c in encrypted_text:
x = ord(c)
x = x - 1
c2 = chr(x)
plain_text = plain_text + c2
print(plain_text)
list2=[encrypted_text]
print(plain_text)
print("the original msgs are :" , list1)
print("the encrypted msgs are :" ,list2)
list1 contains whatever strings the user enters in response to the input prompt.
Then your first for loop iterates over list1. c takes on values which are the elements of list1. Then you use ord on c. Your intent, I expect, is to use ord on the elements of c, instead. Try adding an additional loop somewhere.
Also, consider organizing your code into functions.
ord() takes single character
for c in list1:
x = ord(c)
but above loop return string as C that's why you are getting error
Corrected Code
list1=[]
list2=[]
i = 0
while not(False):
plain_text = input ("Enter any string ")
if (plain_text !='q'):
list1.append(plain_text)
i=i+1
else:
break
encrypted_text = ""
for c in list1: #Changed Code
for c1 in c:
x = ord(c1)
x = x + 1
c2 = chr(x)
encrypted_text = encrypted_text + c2
print(encrypted_text)
#Decryption
encrypted_text = "Uijt!jt!b!uftu/!BCD!bcd"
plain_text = ""
for c in encrypted_text:
x = ord(c)
x = x - 1
c2 = chr(x)
plain_text = plain_text + c2
print(plain_text)
list2=[encrypted_text]
print(plain_text)
print("the original msgs are :" , list1)
print("the encrypted msgs are :" ,list2)
I am trying to make a cryptography program.
When I run this program and insert for example abc with shift 2 it will return cde which is good. But I tried to insert xyz aswell with shift 3 and instead of shifting correctly abc it returns aaa. This also happens if I use shift 2 then it returns zaa.
How can I adjust my program to correctly start from the beginning when the alphabet is done with the ASCII tabel?
shift = int(input("Please insert a number you want to shift the characters with: "))
end = ""
for x in alf:
ascii = ord(x)
if ascii >= 97 and ascii <= 122:
res = ascii + shift
if res > 122:
res = 0 + 97
min = res + shift
end = end + chr(min)
print (end)
It is because your logic expression is wrong. Here is an example that will allow any positive integer as right shift, beginning again at a again. And it can be very much optimized (hint: use modulo operator), but this is with minor changes to your code and numerics written out loud.
for x in alf:
ascii = ord(x)
if ascii >= 97 and ascii <= 122:
res = ascii + shift
while res > 122:
res = res - (122 - 97) - 1
end = end + chr(res)
elif chosenA == 2:
print('''You have chosen to decrypt a message,''')
print("Please enter the name of the file you wish to decrypt")
a = raw_input()
with open(a + '.txt') as text:
lar = text.read()
print(lar)
MS = 0
print("oi drongo enter ya key")
b = raw_input()
for c in b:
f = ord(c)
MS = MS + f
geek = (MS / 8) - 32
#print(geek)
nlar = ''
for c in lar:
g = ord(c)
if g > 126:
g -= 94
g -= geek
f = unichr(g)
print(f)
During the "for c in lar:" I am trying to get the characters in the file to be converted to ascii values using ord() and then if they are greater than 126 (the alphabet) remove 94 from the value then take geek(the offset factor generated from an 8 character key) away from the ascii value so it will be returned to text that was originally encrypted, if you want the full code just say and I'll provide it if it will help.
I'm writing a function to shift text by 13 spaces. The converted chars need to preserve case, and if the characters aren't letters then they should pass through unshifted. I wrote the following function:
def rot13(str):
result = ""
for c in str:
if 65 <= ord(c) <= 96:
result += chr((ord(c) - ord('A') + 13)%26 + ord('A'))
if 97 <= ord(c) <= 122:
result += chr((ord(c) - ord('a') + 13)%26 + ord('a'))
else:
result += c
print result
What I have found is that lowercase letters and non-letter characters work fine. However, when the function is applied to uppercase chars the function returns the shifted char FOLLOWED BY the original char. I know there are plenty of solutions to this problem on SO, but this specific error has me wondering what's wrong with my logic or understanding of chars and loops in python. Any help appreciated.
You are missing the "else" statement, so if the first if "fires" (c is an uppercase letter) then the "else" from the second if also "fires" (and concatenates the uppercase letter, as ord(c) is not between 97 and 122)
def rot13(str):
result = ""
for c in str:
if 65 <= ord(c) <= 96:
result += chr((ord(c) - ord('A') + 13)%26 + ord('A'))
elif 97 <= ord(c) <= 122:
result += chr((ord(c) - ord('a') + 13)%26 + ord('a'))
else:
result += c
print result
Also, uppercase characters end with ord('Z')==90, ASCII characters between 91 and 96 are not letters. Function should also return the value, not print it (unless it is called print_rot13). Your function is also inconsistent - you use ord('A') in calculations, but actual, hard-coded value in if (65) you should decide on one of these.
def rot13(str):
a = ord('a')
z = ord('z')
A = ord('A')
Z = ord('Z')
result = ""
for c in str:
symbol = ord(c)
if A <= symbol <= Z:
result += chr((symbol - A + 13)%26 + A)
elif a <= symbol <= z:
result += chr((symbol - a + 13)%26 + a)
else:
result += symbol
return result
This way it only assume, that lower and upper case letters are arranged in consistent blocks, but nothing about their actual ord values.
This is an (rather contrived) one-liner implementation for the caesar cipher in python:
cipher = lambda w, s: ''.join(chr(a + (i - a + s) % 26) if (a := 65) <= (i := ord(c)) <= 90 or (a := 97) <= i <= 122 else c for c in w)
word = 'Hello, beautiful World!'
print(cipher(word, 13)) # positive shift
# Uryyb, ornhgvshy Jbeyq!
word = 'Uryyb, ornhgvshy Jbeyq!'
print(cipher(word, -13)) # -13 shift means decipher a +13 shift
# Hello, beautiful World!
It rotates only ascii alpha letters, respects upper/lower case, and handles positive and negative shifts (even shifts bigger that the alphabet).
More details in this answer.