I'm writing code so you can shift text two places along the alphabet: 'ab cd' should become 'cd ef'. I'm using Python 2 and this is what I got so far:
def shifttext(shift):
input=raw_input('Input text here: ')
data = list(input)
for i in data:
data[i] = chr((ord(i) + shift) % 26)
output = ''.join(data)
return output
shifttext(3)
I get the following error:
File "level1.py", line 9, in <module>
shifttext(3)
File "level1.py", line 5, in shifttext
data[i] = chr((ord(i) + shift) % 26)
TypError: list indices must be integers, not str
So I have to change the letter to numbers somehow? But I thought I already did that?
You are looping over the list of characters, and i is thus a character. You then try to store that back into data using the i character as an index. That won't work.
Use enumerate() to get indexes and the values:
def shifttext(shift):
input=raw_input('Input text here: ')
data = list(input)
for i, char in enumerate(data):
data[i] = chr((ord(char) + shift) % 26)
output = ''.join(data)
return output
You can simplify this with a generator expression:
def shifttext(shift):
input=raw_input('Input text here: ')
return ''.join(chr((ord(char) + shift) % 26) for char in input)
But now you'll note that your % 26 won't work; the ASCII codepoints start after 26:
>>> ord('a')
97
You'll need to use the ord('a') value to be able to use a modulus instead; subtracting puts your values in the range 0-25, and you add it again afterwards:
a = ord('a')
return ''.join(chr((ord(char) - a + shift) % 26) + a) for char in input)
but that will only work for lower-case letters; which might be fine, but you can force that by lowercasing the input:
a = ord('a')
return ''.join(chr((ord(char) - a + shift) % 26 + a) for char in input.lower())
If we then move asking for the input out of the function to focus it on doing one job well, this becomes:
def shifttext(text, shift):
a = ord('a')
return ''.join(chr((ord(char) - a + shift) % 26 + a) for char in text.lower())
print shifttext(raw_input('Input text here: '), 3)
and using this on the interactive prompt I see:
>>> print shifttext(raw_input('Input text here: '), 3)
Input text here: Cesarsalad!
fhvduvdodgr
Of course, now punctuation is taken along. Last revision, now only shifting letters:
def shifttext(text, shift):
a = ord('a')
return ''.join(
chr((ord(char) - a + shift) % 26 + a) if 'a' <= char <= 'z' else char
for char in text.lower())
and we get:
>>> print shifttext(raw_input('Input text here: '), 3)
Input text here: Ceasarsalad!
fhdvduvdodg!
Looks you're doing cesar-cipher encryption, so you can try something like this:
strs = 'abcdefghijklmnopqrstuvwxyz' #use a string like this, instead of ord()
def shifttext(shift):
inp = raw_input('Input text here: ')
data = []
for i in inp: #iterate over the text not some list
if i.strip() and i in strs: # if the char is not a space ""
data.append(strs[(strs.index(i) + shift) % 26])
else:
data.append(i) #if space the simply append it to data
output = ''.join(data)
return output
output:
In [2]: shifttext(3)
Input text here: how are you?
Out[2]: 'krz duh brx?'
In [3]: shifttext(3)
Input text here: Fine.
Out[3]: 'Flqh.'
strs[(strs.index(i) + shift) % 26]: line above means find the index of the character i in strs and then add the shift value to it.Now, on the final value(index+shift) apply %26 to the get the shifted index. This shifted index when passed to strs[new_index] yields the desired shifted character.
Martijn's answer is great. Here is another way to achieve the same thing:
import string
def shifttext(text, shift):
shift %= 26 # optional, allows for |shift| > 26
alphabet = string.lowercase # 'abcdefghijklmnopqrstuvwxyz' (note: for Python 3, use string.ascii_lowercase instead)
shifted_alphabet = alphabet[shift:] + alphabet[:shift]
return string.translate(text, string.maketrans(alphabet, shifted_alphabet))
print shifttext(raw_input('Input text here: '), 3)
It's easier to write a straight function shifttext(text, shift). If you want a prompt, use Python's interactive mode python -i shift.py
> shifttext('hello', 2)
'jgnnq'
Tried with Basic python.
may useful for someone.
# Caesar cipher
import sys
text = input("Enter your message: ")
cipher = ''
try:
number = int(input("Enter Number to shift the value : "))
except ValueError:
print("Entered number should be integer. please re0enter the value")
try:
number = int(input("Enter Number to shift the value : "))
except:
print("Error occurred. please try again.")
sys.exit(2)
for char in text:
if not char.isalpha():
flag = char
elif char.isupper():
code = ord(char) + number
if 64 < code <= 90:
flag = chr(code)
elif code > 90:
flag = chr((code - 90) + 64)
elif char.islower():
code = ord(char) + number
if 96 < code <= 122:
flag = chr(code)
elif code > 122:
flag = chr((code - 122) + 96)
else:
print("not supported value by ASCII")
cipher += flag
print(cipher)
Related
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 months ago.
Improve this question
I am trying to make a program that shifts the characters of a message to the right of its position in the alphabet. For example: the input is "abc" and the output would be "bcd".
Currently this is the code:
import string
alphabet = list(string.ascii_lowercase)
codelist = []
code = input("input text message: ")
for char in code:
codelist.append(char)
for x in codelist:
for y in alphabet:
if y == x and x != " ":
x = alphabet[alphabet.index(y) + 1]
Traceback:
Traceback (most recent call last):
File "C:\Users\User\PycharmProjects\pythonProject1\file.py", line 12, in <module>
x = alphabet[alphabet.index(y) + 1]
IndexError: list index out of range
This is a Caesar shift. Here is a Caesar shift implementation handling spaces, digits, and alphabetical characters. Just give it a string and the "shift" that you want the characters to change by.
# a function that takes prompts the user for a string and a shift value
# and returns the encoded string
def shift():
# prompt the user for a string
string = input("Enter a string: ")
# prompt the user for a shift value
shift = int(input("Enter a shift value: "))
# create an empty string
new_string = ""
# shift string based on shift value
for i in string:
# if the character is a space, add it to the new string
if i == " ":
new_string += i
# if the character is a lowercase letter, shift it
elif i.islower():
# if the character is shifted past z, wrap around to a
if ord(i) + shift > ord("z"):
new_string += chr(ord(i) + shift - 26)
# otherwise, shift the character
else:
new_string += chr(ord(i) + shift)
# if the character is an uppercase letter, shift it
elif i.isupper():
# if the character is shifted past Z, wrap around to A
if ord(i) + shift > ord("Z"):
new_string += chr(ord(i) + shift - 26)
# otherwise, shift the character
else:
new_string += chr(ord(i) + shift)
# if the character is a number, shift it
elif i.isdigit():
# if the character is shifted past 9, wrap around to 0
if ord(i) + shift > ord("9"):
new_string += chr(ord(i) + shift - 10)
# otherwise, shift the character
else:
new_string += chr(ord(i) + shift)
# if the character is a special character, shift it
else:
new_string += chr(ord(i) + shift)
# return the new string
print("DEBUG: " + new_string)
# call the function
shift()
Actually, your code will break if someone enters 'z' in their input your code will break. Also, if someone enters an uppercase letter then your code will just skip that uppercase letter. You can solve these small errors by changing the input to lowercase form like this:
code = input('input text message: ')
code = code.lower()
For the second error you can add an if statement. So, whenever it faces 'z' in the input it will just specify the value of char to 'a'
You can achieve this like this
if y == x and x != " " and x !="z":
char = alphabet[alphabet.index(y) + 1]
moved += char
elif y == x and x == "z":
char = 'a'
moved +=char
If you are wondering about that moved variable then this is just a variable storing the shifted letters for example if the input is 'The' then for every iteration the shifted chracter will be added to the moved variable. And the value of moved variable will update like this
1. u
2. ui
3. uif
After the program ends you should also print this value to the console using the print statement.
print(moved)
Your code will now look like this:
import string
alphabet = list(string.ascii_lowercase)
codelist = []
moved = ""
code = input("input text message: ")
code = code.lower()
for char in code:
codelist.append(char)
for x in codelist:
for y in alphabet:
if y == x and x != " " and x !="z":
char = alphabet[alphabet.index(y) + 1]
moved += char
elif y == x and x == "z":
char = 'a'
moved +=char
print(moved)
You could do this simply with ord and slicing
alphabet = string.ascii_lowercase
codelist = []
code = input("input text message: ")
code = code.lower() # make sure user inputs values between a-z
alphabet[ord(code[0])-ord('a')+1 : ord(code[0])-ord('a')+len(code)+1]
# for abc -> bcd and xyz -> yz
I was trying this code:
str = input("Enter the string:")
num = input("By how much you want to increment:")
x = int(str) + num
print(char(num))
but this throws a traceback, What will be the correct code and what if the person enters (z + 1) i.e. how will the code be fixed around only the 26 alphabets.
Thank you
You can use ord to get ascii of them and chr to get back the value using ascii value
def inc_letter(char, inc):
start_char = ord('a') if char.islower() else ord('A')
start = ord(char) - start_char
offset = ((start + inc) % 26) + start_char
result = chr(offset)
return result
str_ = input("Enter the string:")
num = int(input("By how much you want to increment:"))
inc_letter(str_, num)
Result:
Enter the string:Z
By how much you want to increment:12
'L'
I am trying to make a decrypt script for a Caeser cipher script to encrypt but can't get it to work. This is my encryption script:
def encrypt(text,s):
result = ""
# traverse text
for i in range(len(text)):
char = text[i]
# Encrypt uppercase characters
if (char.isupper()):
result += chr((ord(char) + s-65) % 26 + 65)
# Encrypt lowercase characters
else:
result += chr((ord(char) + s - 97) % 26 + 97)
return result
#def decrypt(ciphertext, s):
text = "0123456789"
s = 4
Cipher=encrypt(text,s)
print("Text : " + text)
print ("Shift : " + str(s))
print ("Cipher: " + encrypt(text,s))
I need help with creating a decrypt script the same way.
Thanks in advance!
Here is some code of mine for a function used to decrypt a ceaser cipher. The approach used when the shift is not known is simply to get every possible value, then pick the one with more then half the decoded words being in the English dictionary. For non alphabetic characters, there is a placeholder character used.
There are some extra parts required, such as the dictionary or extra functions / lists so I will include them in the below links.
A note, it does only work for on lowercase letters however, I do hope it will help you to understand the logic a bit better.
def Decode(message, shift=-1):
"""
Decodes a message from a caesar cipher
Params:
- message (str) : Message to decode
Optional Params:
- shift (int) : If shift is known
Returns:
- decodedMessage (str) : The decoded message
"""
decodedMessage = ''
message = message.lower() # lowercase is easier to work with
# If the shift is known it is simple to decode
if shift != -1:
for letterIndex in range(len(message)):
if message[letterIndex] in [' ', '!', '?', '.', '-', ',', '_']:
decodedMessage += message[letterIndex]
else:
try:
index = ALPHABET.index(message[letterIndex]) - shift
# If the index is smaller then ALPHABET, handle it
while index < 0:
index += len(ALPHABET)
decodedMessage += ALPHABET[index]
except Exception as e:
print("A problem occured:", e)
decodedMessage += '?'
return decodedMessage
else: #If shift is not known, figure it out thru brute force
data = read_json('words_dictionary')
for i in range(len(ALPHABET)):
decodedMessage = Decode(message, i+1)
wordList = decodedMessage.split(" ")
try:
# Loop over words counting english words
count = 0
for word in wordList:
if word in data.keys():
count += 1
# More accurate this way compared to only one word checks
if count > len(wordList) / 2:
return decodedMessage
except KeyError:
continue
Full code here
Word dictionary here
I have to create a program that gets a string, and an integer n; it will increment each character of the string by n characters; for example, if the string is "abc" and n=1, the output would be "bcd", if n=2, it'd be "cde".
So far I have written this code
string = list( input( "Insert a string, it will be codified: " ) )
n = int( input( "Insert an integer, each string's character will be increased by that number: " ) )
for characterIndex in range( len( string ) ):
string[characterIndex] = chr( ord( string[characterIndex] ) + n )
print( ''.join( string ) )
Nonetheless, if I input "xyz" and n=1, I get "yz{", which makes sense since ascii's next character to "z" is "{". You can imagine that for a higher n, it gets worse; I have been trying to solve this problem for any n using modulo, tried to take advantage from the fact that there are 26 letters, but I'm still unable to find a mathematical increment that detects when the string has been incremented further than "z", so it "gets back" to "a".
Any recommendations? Thanks in advance.
It's kind of cheating, but here's the approach I would take:
def string_bump(s):
letter_list = "abcdefghijklmnopqrstuvwxyza" #note the extra 'a' at the end
old_positions = []; new_positions = []
for character in s:
old_positions.append(letter_list.find(character))
for pos in old_positions:
new_positions.append(pos+1)
new_string = ""
for pos in new_positions:
new_string += letter_list[pos]
return new_string
for s in ["abc", "bcd", "xyz"]:
print("before:", s, "after:", string_bump(s))
prints:
before: abc after: bcd
before: bcd after: cde
before: xyz after: yza
Basically, I scan the string to convert the characters to positions in the alphabet string; add 1 to each position; and rebuild the string from those positions. The "cheat" is adding an extra 'a' so a position-25 (counting from 0) 'z' translates to that extra position-26 'a'.
If that offends you, you could leave off the extra 'a' and instead just take another pass at the list of positions and when you see "26" (which would be past the end of the letter_list without the 'a'), knock it down to zero.
This is just a proof-of-concept for your example; to support an arbitrary shift, you'd extend the letter_list out for the full alphabet, and use modulo on the input (e.g. n = n%26) to ensure the input stayed in range.
Also, I would actually use list expressions in place of the for loops, but you may not have encountered those yet, so I used the more explicit for loops instead above.
Let's break it down so that individual steps with named variables make it clear what you're dealing with:
asciiValue = ord(string[characterIndex])
alphabetIndex = asciiValue - ord('a')
alphabetIndex = (alphabetIndex + n) % 26
asciiValue = alphabetIndex + ord('a')
string[characterIndex] = chr(asciiValue)
Note that the above assumes that your input string is composed only of lowercase ASCII letters. For uppercase characters, you'd need to subtract (and re-add) ord('A') instead.
Integrating it into your existing code:
def shift_letter(letter, n):
asciiValue = ord(letter)
alphabetIndex = asciiValue - ord('a')
alphabetIndex = (alphabetIndex + n) % 26
asciiValue = alphabetIndex + ord('a')
return chr(asciiValue)
string = list( input( "Insert a string, it will be codified: " ) )
n = int( input( "Insert an integer, each string's character will be increased by that number: " ) )
for characterIndex in range( len( string ) ):
string[characterIndex] = shift_letter(string[characterIndex], n)
print( ''.join( string ) )
I thought since we needed to encrypt only the alphabets I created a list of alphabets and looped them as below. This way when you input alphabets only alphabets shifted by the given number comes out even if the shift is large.
print("welcome to encryptor!!")
print("Do you want to encrypt or decrypt")
s = int(input("Press 1 for encrypt and 2 for decrypt: "))
alpha = list("abcdefghijklmnopqrstuvwxyz")
print(alpha)
def encrypt():
string = list(input("Enter your string without space to encrypt: "))
print(string)
string1 = []
n = int(input("Enter the value key for caesar crypt: "))
for characterIndex in range(len(string)):
for i in range(len(alpha)):
if string[characterIndex] == alpha[i]:
if((i + n)+1) >= 26:
string1.append(alpha[(i+n) % 26])
else:
string1.append(alpha[i+n])
else:
continue
print(''.join(string1))
This code does produce the desired ouput..
Here is the modified answer from the comments:
c = chr((ord(a) - 97) % 25 + 97)
I am new to programming and I need some help for an free online tutorial to learn Python. I am building my own method to convert a an input string to all lower cases. I cannot use the string.lower() method. In the code I have so far I cannot figure out how to separate the input string into characters that can be inputed into my character converter lowerChar(char).
string=input #input string
def lowerChar(char): #function for converting characters into lowercase
if ord(char) >= ord('A') and ord(char)<=ord('Z'):
return chr(ord(char) + 32)
else:
return char
def lowerString(string): #function for feeding characters of string into lowerChar
result = ""
for i in string:
result = result + lowerChar(string[i])
return result
You are really close:
def lowerString(string):
result = ""
for i in string:
# i is a character in the string
result = result + lowerChar(i)
# This shouldn't be under the for loop
return result
Strings are iterable just like lists!
Also, make sure to be careful about your indentation levels, and the number of spaces you use should be consistent.
You are returning only the first letter, you have to return in a outer scope, try this, also it is better to use += instead of result = result + lowerChar(i)
def lowerString(string): #function for feeding characters of string into lowerChar
result = ""
for i in string:
result += lowerChar(i)
return result
print lowerString("HELLO") #hello
A tip: You don't need to use ord(). Python can directly do the following comparision:
if char >= 'A' and char<='Z':
My solution:
string = input("Input one liner: ")
def lowerChar(char):
if char >= 65 and char <= 90:
char = chr(char + 32)
return char
else:
char = chr(char)
return char
def lowerString(string):
result = ""
for i in range(0, len(string)):
result = result + lowerChar(ord(string[i]))
return result
print(lowerString(string))
Try something like this:
def lowerChar(c):
if 'A' <= c <= 'Z':
return chr(ord(c) - ord('A') + ord('a'))
else:
return c
def lowerString(string):
result = ""
x=0
for i in string:
while x < len(string):
result = result + lowerChar(string[x])
x+=1
return result