I am programming a Caeser Cipher encoder/decoder for my computer science class in Python 3 and I'm struggling to find out how to exclude spaces when each character is shifted.
message = input("type in a message")
messageInt = float(input("type in an integer"))
newStrs = []
for letter in message:
x = ord(letter)
x = int(x + messageInt)
newStrs.append(chr(x))
print("".join(newStrs))
This happends when I try to use an example sentance with spaces, I've tried looking online for answers but I wasn't able to find anything that seemed to work in Python 3 or would output what my teacher expects.
type in a message hello there
type in an integer 3
#khoor#wkhuh
Process finished with exit code 0
Use a simple list comprehension with a ternary to check for the spaces:
message = input("type in a message")
messageInt = int(input("type in an integer"))
print("".join([c if c == ' ' else chr((ord(c)-ord('a')+messageInt)%26+ord('a')) for c in message]))
You can easily generalize to a whitelist of characters using a set:
keep = set(' .,?!')
print("".join([c if c in keep else chr((ord(c)-ord('a')+messageInt)%26+ord('a')) for c in message]))
Output:
khoor wkhuh
To exclude spaces when shifting the characters in your message, you can simply add an if statement to your loop that checks if the current letter is a space. If it is, you can skip the shifting step and just append the space to the newStrs list.
I modified your code as an example (code updated):
# Get the message and shift amount from the user
message = input("type in a message: ")
shift = int(input("type in an integer: "))
# Create a list to store the shifted characters
new_str = []
# Iterate through each character in the message
for letter in message:
# Check if the character is a space
if letter == " ":
# If it is, append a space to the new string and skip the rest of the loop
new_str.append(" ")
continue
# Shift the character by the specified amount
# First, get the ASCII value of the character
x = ord(letter)
# Shift the character and wrap around the alphabet if necessary
x = (x + shift - 97) % 26 + 97
# Convert the shifted ASCII value back to a character and append it to the new string
new_str.append(chr(x))
# Join the shifted characters into a single string and print it
print("".join(new_str))
If you are wondering whats going on with
x = (x + shift - 97) % 26 + 97
This will shift all characters except spaces, so the output will preserve the spaces in the original message.
x = (x + shift - 97) % 26 + 97
This line of code is used to shift the ASCII value of a character by a specified amount and wrap around the alphabet if necessary.
First, the value of x is added to the value of shift:
x + shift
Then, 97 is subtracted from the result:
x + shift - 97
The result is then passed to the % operator, which returns the remainder of the division of the left operand by the right operand. In this case, the remainder of the division of x + shift - 97 by 26 is calculated:
(x + shift - 97) % 26
Finally, 97 is added back to the result:
(x + shift - 97) % 26 + 97
This has the effect of shifting the character by the specified amount, wrapping around the alphabet if necessary, and ensuring that the resulting ASCII value is in the range 97 to 122 (inclusive).
For example, if the value of x is 120 (the ASCII value of 'x'), the value of shift is 3, and the line of code is executed, the following steps will be taken:
120 + 3 = 123
123 - 97 = 26
26 % 26 = 0
0 + 97 = 97
The final result, 97, is the ASCII value of 'a', so the resulting character will be 'a'.
Related
As above, am learning Python3 and going through a message decoding problem. I have my code working for letters only, but when I introduce a string with a space (' ') my solution to try and hardcode the ASCII values of space and punctuation in to my nest if loop (within a for loop) I get the IndexError: list index out of range. I understand the error itself, but not how my code is triggering it.
This line of code is my attempt at creating a rule for space:
if newnumberval == 32 + 107:
outputmessage.append(' ')
This is my code so far:
import string
alphabet = list(string.ascii_lowercase)
#check each letter in message, take 10 from its alphanumeric value, add new val
# to outputlist
# if val - 10 is lower than 0, newval(negative) is taken from 26
# remove and store spaces and punctuation
# solution1: hardcode spaces and punctuation values
# i.e. if newnumberval(" ")= 22 then outputmessage.append(" ")
# solution2: if letter not in alphabet, outputmessage.append(letter)
def decodemessage(message):
outputmessage = []
for letter in list(message):
numberval = ord(letter) - 97
newnumberval = numberval - 10
if newnumberval == 32 + 107:
outputmessage.append(' ')
elif newnumberval < 0:
newnumberval += 26
outputmessage.append(alphabet[newnumberval])
else:
outputmessage.append(alphabet[newnumberval])
return outputmessage
print(decodemessage('hello '))
userPhrase = input('Enter a single word phrase to be encrypted: ')
userPhrase = userPhrase.lower()
key = int(input('Enter a key: '))
encryptedPhrase = ''
for character in userPhrase:
x = ord(character) - 97
x += key
x = x % 26
encryptedPhrase += chr(x + 97)
print('Encrypted phrase is ' + encryptedPhrase)
I've written a simple encryption program above, mainly following guides online, however all the material I've read through doesn't adequately explain why the ASCII value of the encrypted character is subtracted/reduced by the ASCII value of A(97). As in the line:
x = ord(character) - 97
Any explanations would be great, thank you in advance!
In ASCII, the lower case alphabet a-z starts at point ord('a') == 97. Therefore, ord(character) - 97 maps a-z to the integer range 0...25.
Your encryption, which is a Caesar cipher, then shifts that range to the right by the value of key, wrapping around due to x = x % 26. So for example, if key is 5, 0 maps to 5, 20 maps to 25, 21 maps to 0, etc.
Turning this modified alphabet back into ASCII characters, you need to add back the code point for ord('a'), hence the chr(x + 97).
Write a program that takes a character as input (a string of length 1), which you should assume is an upper-case character; the output should be the next character in the alphabet. If the input is 'Z', your output should be 'A'. (You will need to use an if statement.)
So far I've tried several codes like this:
chr = input()
if chr == '65':
x = chr(ord(chr) + 1)
print(chr(65) + 1)
It says it prints with no output, just unsure how to get to the the right output. Im very new to programming.
This should work:
my_chr = ord(input())
if my_chr == 90:
print('A')
else:
print(chr(my_chr+1))
It takes the input letter (A-Z) and gets its ord() value. It then checks to see if the value is equal to Z (ord('Z') == 90) and prints A otherwise, it increments it by 1 then turns it back to a string and prints it.
You can use the following idea:
A = 65
Z = 90
If you subtract ord('A') from the input, you reduce the range to [0, 25]
So, you need to define the output inside the range [0, 25]. To avoid getting out this range, you should use '%'.
char_input = input()
return chr((ord(char_input) - ord('A') + 1) % 26 + ord('A'))
it means that, giving the input, you will subtract the value of ord('A') to "fix" the range and, after that, add + 1. You will take % 26 to avoid getting out the range. After all of that, add ord('A') again.
Hope this is what you are looking for
_chr = input('Enter character(A-Z): ')
if _chr == 'Z':
print('A')
else:
print(chr(ord(_chr) + 1))
alpha=input()
if alpha =='Z': print('A')
else:print(chr(ord(alpha)+1))
"You will need to use an if statement"
The below method is using ascii_letters.
import string
// returns a string of all the alphabets
// abcdefghijklmnopqrstuvwxyz"
result = string.ascii_letters
// get the index of the input alphabet and return the next alphabet in the results string.
// using the modulus to make sure when 'Z' is given as the input it returns to the first alphabet.
result[(result.index(alphabet.lower()) + 1) % 26].upper()
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)
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 :)