I want print only letters but it's prints special characters of ASCII. My code:
import string
def caesar(shift):
alphabet = string.ascii_lowercase + string.ascii_uppercase
dict={}
emptylist=[]
int(shift)
for x in alphabet:
emptylist.append(x)
code = ""
for letters in emptylist:
code = chr(ord(letters) + shift)
dict[letters]=code
return dict
caesar(12)
My output:
'm': 'y', 'l': 'x', 'o': '{', 'n': 'z', 'q': '}', 'p': '|', 's': '\x7f', 'r': '~', 'u': '\x81', 't': '\x80', 'w': '\x83', 'v': '\x82', 'y': '\x85', 'x': '\x84', 'z': '\x86'
Correct output:
'm': 'y', 'l': 'x', 'o': 'a', 'n': 'z', 'q': 'c', 'p': 'b', 's': 'e', 'r': 'd', 'u': 'g', 't': 'f', 'w': 'i', 'v': 'h', 'y': 'k', 'x': 'j', 'z': 'l'
Using ord() and changing the character code won't restrict the resulting character to your dictionary.
I'd just find the index of the letter in your dictionary, shift it, and use the modulo operator:
import string
def caesar(shift):
alphabet = string.ascii_uppercase # <- Change it back to what you had before
# and see what will happen.
mapping = {}
for letter in alphabet:
index = alphabet.index(letter)
mapping[letter] = alphabet[(index + shift) % len(alphabet)]
return mapping
Test (dictionaries don't preserve order, so it's pretty hard to read):
>>> caesar(12)
{'A': 'M', 'C': 'O', 'B': 'N', 'E': 'Q', 'D': 'P', 'G': 'S', 'F': 'R', 'I': 'U', 'H': 'T', 'K': 'W', 'J': 'V', 'M': 'Y', 'L': 'X', 'O': 'A', 'N': 'Z', 'Q': 'C', 'P': 'B', 'S': 'E', 'R': 'D', 'U': 'G', 'T': 'F', 'W': 'I', 'V': 'H', 'Y': 'K', 'X': 'J', 'Z': 'L'}
Let's look at one error in particular: o: '{'.
Notice that ord('o') is 111, so let's look at the chr of integers in the range(111,130):
Starting at o, shifting by 12, takes you to the { character:
In [75]: ' '.join([chr(x) for x in range(111,130)])
Out[75]: 'o p q r s t u v w x y z { | } ~ \x7f \x80 \x81'
^ 1 2 3 4 5 6 7 8 9 ...12
So the reason why you are getting incorrect output is because your formula
code = chr(ord(letters) + shift)
isn't taking into account what happens if the shift bounces you out of the ords associated with a-z or A-Z. (Note that the ord ranges for a-z and A-Z are not contiguous either!)
Here is a hint on how to fix:
In [82]: alphabet = string.ascii_lowercase + string.ascii_uppercase
In [83]: alphabet.index('o')
Out[83]: 14
In [84]: alphabet[alphabet.index('o')+12]
Out[84]: 'A'
but
In [85]: alphabet[alphabet.index('O')+12]
results in IndexError: string index out of range. That's because len(alphabet) is 52, and
In [91]: alphabet.index('O')+12
Out[91]: 52
Somehow we need 52 to wrap back around to 0. You can do that with the % modulo operator:
In [92]: 52 % 52
Out[92]: 0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With