Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why my code prints others characters? cipher

Tags:

python

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'

like image 226
dragon_ball Avatar asked Feb 20 '26 03:02

dragon_ball


2 Answers

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'}
like image 133
Blender Avatar answered Feb 21 '26 17:02

Blender


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
like image 38
unutbu Avatar answered Feb 21 '26 17:02

unutbu



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!