Reputation: 357
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?
Upvotes: 9
Views: 65378
Reputation: 250951
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 then 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.
Upvotes: 11
Reputation: 1
This solution works just fine.
def rotate(text, key):
result = []
for char in text:
if char.isalpha(): # Check if the character is alphabetic
shift = 65 if char.isupper() else 97 # ASCII code for 'A' or 'a'
new_char = chr((ord(char) - shift + key) % 26 + shift)
else:
new_char = char # Keep non-alphabetic characters unchanged
result.append(new_char)
return ''.join(result)
Upvotes: 0
Reputation: 176
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)
Upvotes: 1
Reputation: 1969
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)
Upvotes: 2
Reputation: 1121864
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!
Upvotes: 11
Reputation: 137574
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'
Upvotes: 1