Trying to wrap caesar cypher (Python) - python

I've tried using "if" statements to skip characters that aren't alphabetical but It keeps ignoring the code and adding the shifted characters. I'm trying to shift the user input by 2 but the encoded-word should not have any special characters so the shift would wrap round back from z-a.
The code below is before I tried "if" statements.
encoded_word = ("")
decoded_word = ("")
def Encoding(text):
global encoded_word
letter_list = list(text)
length_list = len(text)
for i in range (0,length_list):
letter_ord = ord(letter_list[i])
encoded_letter = chr(letter_ord+2)
encoded_word = (encoded_word + encoded_letter)
print ("The encoded word is now:",encoded_word)
def Decoding(text):
global decoded_word
letter_list = list(text)
length_list = len(text)
for i in range (0,length_list):
letter_ord = ord(letter_list[i])
decoded_letter = chr(letter_ord-2)
decoded_word = (decoded_word + decoded_letter)
print ("The decoded word is:",decoded_word)
decode_encode = str(input("Would you like to encode or decode text? encode/decode: "))
if decode_encode == "encode":
user_word = str(input("Enter in a word to encode: "))
Encoding(user_word)
if decode_encode == "decode":
user_word = str(input("Enter in the encoded word: "))
Decoding(user_word)

to check if a character is a letter you can use isalpha().
For example should print just d and f:
list = ["3","2","-","1","4","5","-","3","d", "f"]
character_list = []
for i in list:
if i.isalpha():
character_list.append(i)
print (character_list)

I think you are on the right track you just to deal with a couple more edge cases such as if the shift amount is greater than 26, or if the shift needs to wrap around, etc. Additionally, string concatenation using + is inefficient since a copy of the existing string needs to be made each concatenation. Therefore, consider appending to a list of characters instead and only creating an output encoded/decoded string at the end:
SHIFT_AMOUNT = 2
def encode(text):
res = []
actual_shift_amount = SHIFT_AMOUNT % 26
for ch in text:
new_letter = ch
if ord('a') <= ord(ch) <= ord('z'):
if (ord(ch) + actual_shift_amount) <= ord('z'):
new_letter = chr(ord(ch) + actual_shift_amount)
else:
new_letter = chr(ord('a') + actual_shift_amount - (ord('z') - ord(ch) + 1))
elif ord('A') <= ord(ch) <= ord('Z'):
if (ord(ch) + actual_shift_amount) <= ord('Z'):
new_letter = chr(ord(ch) + actual_shift_amount)
else:
new_letter = chr(ord('A') + actual_shift_amount - (ord('Z') - ord(ch) + 1))
res.append(new_letter)
return ''.join(res)
def decode(text):
res = []
actual_shift_amount = SHIFT_AMOUNT % 26
for ch in text:
new_letter = ch
if ord('a') <= ord(ch) <= ord('z'):
if (ord(ch) - actual_shift_amount) >= ord('a'):
new_letter = chr(ord(ch) - actual_shift_amount)
else:
new_letter = chr(ord('z') - actual_shift_amount + (ord(ch) - ord('a') + 1))
elif ord('A') <= ord(ch) <= ord('Z'):
if (ord(ch) - actual_shift_amount) >= ord('A'):
new_letter = chr(ord(ch) - actual_shift_amount)
else:
new_letter = chr(ord('Z') - actual_shift_amount + (ord(ch) - ord('A') + 1))
res.append(new_letter)
return ''.join(res)
decode_or_encode = input("Would you like to encode or decode text? encode/decode: ").lower()
if decode_or_encode == "encode":
user_word = input("Enter in a word to encode: ")
print(encode(user_word))
elif decode_or_encode == "decode":
user_word = input("Enter in the encoded word: ")
print(decode(user_word))
Example Usage encode:
Would you like to encode or decode text? encode/decode: encode
Enter in a word to encode: Yoruke-Stack-Overflow
Aqtwmg-Uvcem-Qxgthnqy
Example Usage decode:
Would you like to encode or decode text? encode/decode: decode
Enter in the encoded word: Aqtwmg-Uvcem-Qxgthnqy
Yoruke-Stack-Overflow
Try it here.

The problem is that when adding or subtracting 2 you do not check if you reached the limit of the alphabet ('a' or 'z'). You should do something like
if encoded_letter > "z":
# do something

The approach you are following is not the best one. However, assuming that you are considering lowercase characters only.
Encoding
replacing
encoded_letter = chr(letter_ord + 2)
with
encoded_ord = letter_ord + 2
if encoded_ord > ord('z'): # after encoding if exceeds from 'z'
difference = encoded_ord - ord('z') # finding how much exceeded from 'z'
encoded_ord = ord('a') + difference + 1 # restart from 'a' again.
encoded_letter = chr(encoded_ord)
Decoding
replacing
decoded_letter = chr(letter_ord-2)
with
decoded_ord = letter_ord - 2
if decoded_ord < ord('a'): # after decoding if deceeds from 'a'
difference = ord('a') - decoded_ord # finding how much deceeded from 'a'
decoded_ord = ord('z') - difference + 1 # restart from 'z' again but backward
decoded_letter = chr(decoded_ord)
should work

Related

Swap upper and lower case with its ASCII value

Im trying to swap letter type with its ASCII value however I am only getting the last word of the string as an output. it also will not accept any string with number values
def get_sentence():
sentence = input("Please input the sentence:")
words = sentence.split(' ')
sentence = ' '.join(reversed(words))
return sentence
ans = ''
def main():
sentence = get_sentence()
ans =''
for s in sentence:
if ord(s) >= 97 and ord(s) <= 122:
ans = ans + chr(ord(s) - 32)
elif ord(s) >= 65 and ord(s) <= 90 :
ans = ans + chr(ord(s) + 32)
else :
ans += ' '
print(ans)
if __name__ == "__main__":
main()
I am not sure if this is the result you want (adding expected output would be helpful next time) but removing the print statement outside the for loop seems to fix it for me.
def get_sentence():
sentence = input("Please input the sentence:")
words = sentence.split(' ')
sentence = ' '.join(reversed(words))
return sentence
ans = ''
def main():
sentence = get_sentence()
ans =''
for s in sentence:
if ord(s) >= 97 and ord(s) <= 122:
ans = ans + chr(ord(s) - 32)
elif ord(s) >= 65 and ord(s) <= 90 :
ans = ans + chr(ord(s) + 32)
else :
ans += ' '
print(ans) # this should be outside!
if __name__ == "__main__":
main()
There's a simpler way to do this, using built-in methods isupper() and islower(). Then you don't need to handle sentences (or punctuation) separately.
def swap_case(sentence: str) -> str:
letters = (
letter.upper() if letter.islower() else letter.lower()
for letter in sentence
)
return "".join(letters)
print(swap_case(get_sentence()))
Notice my function also returns the result rather than printing it. And it takes input of the sentence, so you can use it in other cases, which makes it more reusable. Not sure why you want the words of the sentence reversed... but ¯\_(ツ)_/¯

Encoding a password with special characters

I am in an into to Programming class and the assignment is in part to shift the letters of a valid password by +1 if it is a letter or number and -1 if it is a !##$ special character. I have most of it working with my below code but I always get the wrong output for the special characters. If I use to the code of anything high like 128 then I get the wrong symbol.
I am using the code from an encryption program from the other week and slowly changing things but I feel like this is too involved for something simple
If I enter the password UMA#augusta2020 I need to get the output VNB?bvhvtub3131 but I either end up with a space, b, or wrong symbol when I change the code input between 26,64,96,128, etc.
I have updated the code to fix small errors
def main():
print("This program validates and encrypts a password")
print()
main()
# The Encryption Function
def cipher_encrypt(plain_text):
encrypted = ""
for c in plain_text:
if c.isupper(): #check if it's an uppercase character
c_index = ord(c) - ord('A')
# shift the current character by key positions
c_shifted = (c_index + 1) % 26 + ord('A')
c_new = chr(c_shifted)
encrypted += c_new
elif c.islower(): #check if its a lowecase character
c_index = ord(c) - ord('a')
c_shifted = (c_index + 1) % 26 + ord('a')
c_new = chr(c_shifted)
encrypted += c_new
elif c.isdigit():
# if it's a number,shift its value
c_new = (int(c) + 1) % 10
encrypted += str(c_new)
else:
# if its neither alphabetical nor a number, -1
c_shifted = (c_index - 1) % 128 + ord('a')
c_new = chr(c_shifted)
encrypted += c_new
return encrypted
plain_text =input("Enter your Password: ")
print()
ciphertext = cipher_encrypt(plain_text)
print()
print("Your Password: ", plain_text)
print()
print("Your password is valid and encrypted it is: ", ciphertext)
print()
Here is a much cleaner approach:
def cipher_encrypt(plain_text):
alpha = 'abcdefghijklmnopqrstuvwxyz'
digits = '0123456789'
puncs = '!"#$%&\'()*+,-./:;<=>?#[\\]^_`{|}~'
encrypted_text = ''
for c in plain_text:
if c.lower() in alpha:
c_index = alpha.index(c.lower())
e_index = (c_index + 1)%len(alpha)
if c == c.lower():
encrypted_text += alpha[e_index]
else:
encrypted_text += alpha[e_index].upper()
elif c in digits:
c_index = digits.index(c)
e_index = (c_index + 1)%len(digits)
encrypted_text += digits[e_index]
else:
c_index = puncs.index(c)
e_index = (c_index +len(puncs) - 1)%len(puncs)
encrypted_text += puncs[e_index]
return encrypted_text
In this approach I deal with each caharcter in plain text by:
Determining idf the char is part of alpha by making use of the c.lower() function to isolate alpha chars and then find an index modulo the len of alpha. Then I determine if I need an uppercase char or lower case in the encrypted text.
I use the same modulo approach for digits, but don't have to worry about upper and lower, finally
I find the index for the punctuations found in the plain_text

Python brute force decryption just with ASCII character set from 32-126 (printable)

Hi all, having immense trouble here and can't figure out where errors are so seeking assistance. I've > pasted my two (best? closest?) attempts below.
I'm attempting a brute-force approach to decryption, but not using just the usual 26 characters of the > alphabet. The intent is to encapsulate the full set of printable characters from ASCII 32 to ASCII 126.
If I can get this written correctly, it should print out a result at the bottom of this post.
Where am I going wrong?
input_string = input('Enter code for decryption: ')
input_list = list(input_string)
shift_value = 0
decryption_index = 0
while shift_value in range(1, 95, 1) :
while decryption_index < len(input_list):
decryption_index = 0
shifter = (ord(input_list[decryption_index]) - ord(" ") - shift_value) % 95
chr_decrypt = chr(ord(input_list[decryption_index]) + shift_value)
input_list[decryption_index] = chr_decryption
decryption_index += 1
shift_value -= 1
input_string = ''.join(input_list)
print ('Shift value',shift_value,' = Decrypted code:' ,input_string)
&...
input_string = input('Please enter code for decryption: ')
input_list = list(input_string)
shift_value = 0
decryption_index = 0
for shift_value in range(1, 95, 1):
for decryption_index in range(len(input_list)):
shifting = (ord(input_list[decryption_index]) - ord(" ") - shift_value) % 95
chr_decryption = chr(shift_value + ord(" "))
input_list[decryption_index] = chr_decryption
decryption_index += 1
input_string = ''.join(input_list)
print('Shift value', shift_value, '= Decrypted code:', input_string)
Example intended output:
Shift value 1 = Decrypted code: xjhwjy%xvznwwjq
(through to)
Shift value 94 = Decrypted code: zljyl{'zx|pyyls
However, I get only:
Shift value 94 = Decrypted code: ~~~~~~~~~~~~~~~
or a blank.
Update as requested; method used to encrypt is:
input_string = input("Please enter string to encrypt: ")
shift_value = int(input("Please enter shift value (1 to 94): "))
total = ""
for char in input_string:
x = ord(char)
x = x + shift_value
while x < 32:
x += 95
while x > 126:
x -= 95
total += chr(x)
print("")
print("Encrypted string:")
print(total)
If you use bruteforce for decryption there is no way you can check which one is correct output. So you need to useshift_value to decrypt the string.
def decrypt(s, key):
ans = ''
for char in s:
x = (ord(char) - ord(' ') - key) % 95
ans += chr(x + ord(' '))
return ans
decrypt('xjhwjy%xvznwwjq', 93) #zljyl{'zx|pyyls
And one more thing In your encryption code you are using while loop to change x value. Loop is not required for this. You can just use if condition.
def encrypt(s, key):
ans = ''
for char in s:
x = ord(char) + key
if x < 32:
x += 95
if x > 126:
x -= 95
ans += chr(x)
return ans
encrypt("zljyl{'zx|pyyls", 93) #xjhwjy%xvznwwjq

Changing Characters in sentence Python whithout library

In my sentence i want :
replace every # by *
skip every ?
if the ascii value of a char is pair so i am transforming into LowerCase + Shift Value ( input user)
if the ascii value of a char is impair so i am transforming into UpperCase + Shift Value ( input user)
Its tell me
line 19, in replace
new = ord(lower(c)) + (shift % 26)
TypeError: ord() expected string of length 1, but NoneType found
def lower(c):
if 'A' <= c <= 'Z':
c = chr(ord(c) + (ord('a') - ord('A')))
def upper(c):
if 'a' <= 'c' <= 'z':
c = chr(ord(c) - (ord('a') - ord('A')))
def replace(text):
new_text = ''
for c in text:
if c == '#':
new_text += '*'
elif c == '?':
continue
elif ord(c) % 2 == 0:
new = ord(lower(c)) + (shift % 26)
if new > ord('z'):
new = (ord('a') + (new - ord('z')))
new_text += chr(new)
elif ord(c) % 2 != 0:
new = ord(upper(c)) + (shift % 26)
if new_text > 'Z':
new_text = chr('Z' + (new_text - 'Z'))
new_text += chr(new)
return new_text
sentence = (input("Please enter a sentence to encrypt:\n"))
shift = int(input("Please enter the size of the shift:\n"))
sentence = replace(sentence)

python caesar chr and ord without newline and just iterate in the alphabet

I have some problem with my caesar code.
1) I don't know how to check if a character is a punctuation and print without sum.
2) print the char on the same line but when it's finished return a newline.
3) Iterate through the alphabet with big number return me a punctuation, how can I do to return just a character?
import sys
import string
def main():
if len(sys.argv) != 2:
print("Usage: caesar.py k")
else:
k = int(sys.argv[1])
if k == 1 or k <= 26:
text = input("plaintext: ");
j = len(text)
for i in range(j):
#check if is a character
if text[i].isalpha:
if text[i].islower():
print(chr(ord(text[i]) + k),end = "")
if text[i].isupper():
print(chr(ord(text[i]) + k),end = "")
elif text[i].punctuation():
print(text[i])
else:
print("You have to introduce a number between 1 and 26")
main()
Try this code:
import string
def encrypt_ceasar(s, shift):
assert abs(shift) < 26, 'shift is between -25 and 25 (inclusive)'
encrypted_s = ''
for char in s:
if char.isalpha():
is_upper = char.isupper()
char = char.lower()
pos_alphabet = ord(char) - ord('a')
new_pos = (pos_alphabet + shift) % 26
encryted_char = chr(ord('a') + new_pos)
if is_upper:
encryted_char = encryted_char.upper()
encrypted_s += encryted_char
else:
encrypted_s += char
return encrypted_s
def decrypt_ceasar(s, shift):
return encrypt_ceasar(s, -shift)
if __name__ == "__main__":
s = 'AbC1$de#zy'
encrypted_s = encrypt_ceasar(s, 3)
print('s:', s)
print('encrypted_s:', encrypted_s)
print('again s:', decrypt_ceasar(encrypted_s, 3))
Output:
s: AbC1$de#zy
encrypted_s: DeF1$gh#cb
again s: AbC1$de#zy

Categories