Why is ROT 13 displaying g in spaces? - python

I am writing code that is based on ROT13 Algorithm but when I have the message as "ROT ALGORITHM" it displays as "EBGgNYTBEVGUZ". I am unsure whether the 'g' is wrong since its meant to be a space between ROT and ALGORITHM?
def rot13(message,shift):
result = ""
for i in range(len(message)):
char = message[i]
if (char.isupper()):
result += chr((ord(char) + shift-13) % 26 + 65)
else:
result += chr((ord(char) + shift-13) % 26 + 97)
return result
shift = 13
message = "ROT ALGORITHM"
print("Shift:", shift)
print(message)
print(rot13(message,shift))

From ROT13 spec, only letters should be affected by the algorithm, here as space is not upper() you go in the else section
You may handle the 2 min usecases : lowercase and uppercase, and just use the alphabet to rotate
from string import ascii_lowercase, ascii_uppercase
def rot13(message, shift):
result = ""
for char in message:
if char in ascii_uppercase:
result += ascii_uppercase[(ascii_uppercase.index(char) + shift) % 26]
elif char in ascii_lowercase:
result += ascii_lowercase[(ascii_lowercase.index(char) + shift) % 26]
else:
result += char
return result

Related

How to replace each letter in a string with a consecutive letter with increasing offset?

Suppose the word is "CAT" and I want the output to be "DCW". Where the C changes to the next letter D and the A changes into the second next letter from A to C and the T changes into the third next letter from T to W.
I am on the first step here:
a = input("Enter a letter: ")
a = chr(ord(a) + 1)
print(a)
You need to loop over the word:
word = 'CAT'
result = ''
for i, a in enumerate(word,1):
result += chr(ord(a) + i)
print(result)
# alternatively, same loop as list comprehension
print(''.join(chr(ord(a) + i) for i, a in enumerate(word,1)))
Out:
DCW
DCW
What you are looking for is called Caesar cypher, but the offset changes with the character's position:
def encrypt(text):
result = ""
for i in range(len(text)):
char = text[i]
if (char.isupper()):
result += chr((ord(char) -65) % 26 + 65 + i + 1)
else:
result += chr((ord(char) - 97) % 26 + 97 + i + 1)
return result
print(encrypt(input()))
Source: https://www.tutorialspoint.com/cryptography_with_python/cryptography_with_python_caesar_cipher.htm
try this :
import string
a =input("Enter a letter: ")
r=''
for i,e in enumerate(a,1):
r=r+string.ascii_lowercase[string.ascii_lowercase.index(e.lower())+i]
print(r.upper())
or in one line like this :
print(''.join(list(string.ascii_lowercase[string.ascii_lowercase.index(e.lower())+i] for i,e in enumerate(a,1) )).upper())
Note: in Python 2, string.ascii_lowercase is string.lowercase.

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

Why is there a %26 (Python)?

I am trying to decipher a text from user without knowing the key in caesar cipher.
I probably understand most of it but I don't get it why they use the mod 26 on line 8
alphabet=['a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z']
print('write the message you want to decode?')
inputString = input()
inputString = inputString.lower()
transAlphabet = {}
def createDict(shift):
for i in range(0,26):
letter = alphabet[i]
transAlphabet[letter]=alphabet[(i+shift)%26]
def encodeMessage(message):
cypherText = ''
for letter in message:
if letter in transAlphabet:
cypherText = cypherText + transAlphabet[letter]
else:
cypherText = cypherText + letter
print(cypherText)
for i in range(0,26):
createDict(i)
encodeMessage(inputString)
Please would be really helpful if someone helps me out thank you!
The modulo %26 is to make the alphabet circular, when you're at z come back at a
Example for alph[(i + shift) % 26] with i=20 and shift=10
without modulo you'll like to reach index 30 in the array and it doesn't not exist
with modulo you'll reach index 30%26 = 4 in the array, letter e
But also your algo is a bt strange, I would have done the shifting on the fly for each car, but your solution may be more efficient for long text as you don't need to compute the shift everytime.
Not computing the shifted alphabet before would look like this
from string import ascii_lowercase
alphabet = ascii_lowercase
def encode_message(message, shift):
cypher_text = ''
for letter in message:
letter_idx = alphabet.index(letter)
cypher_text = cypher_text + alphabet[(letter_idx + shift) % 26]
return cypher_text
def decode_message(message, shift):
cypher_text = ''
for letter in message:
letter_idx = alphabet.index(letter)
cypher_text = cypher_text + alphabet[(26 + letter_idx - shift) % 26]
return cypher_text

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

Yet another caesar cipher in python

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.

Categories