Caesar ciphers
[cipher-training.git] / cipher.py
1 """A set of ciphers with implementations for both enciphering and deciphering
2 them. See cipherbreak for automatic breaking of these ciphers
3 """
4
5 import string
6 # import collections
7 # from enum import Enum
8 # from itertools import zip_longest, cycle, chain
9
10 from language_models import unaccent, sanitise
11
12
13 def caesar_encipher_letter(accented_letter, shift):
14 """Encipher a letter, given a shift amount
15
16 >>> caesar_encipher_letter('a', 1)
17 'b'
18 >>> caesar_encipher_letter('a', 2)
19 'c'
20 >>> caesar_encipher_letter('b', 2)
21 'd'
22 >>> caesar_encipher_letter('x', 2)
23 'z'
24 >>> caesar_encipher_letter('y', 2)
25 'a'
26 >>> caesar_encipher_letter('z', 2)
27 'b'
28 >>> caesar_encipher_letter('z', -1)
29 'y'
30 >>> caesar_encipher_letter('a', -1)
31 'z'
32 >>> caesar_encipher_letter('A', 1)
33 'B'
34 >>> caesar_encipher_letter('é', 1)
35 'f'
36 """
37 letter = unaccent(accented_letter)
38 if letter in string.ascii_letters:
39 if letter in string.ascii_uppercase:
40 alphabet_start = ord('A')
41 else:
42 alphabet_start = ord('a')
43 return chr(((ord(letter) - alphabet_start + shift) % 26) +
44 alphabet_start)
45 else:
46 return letter
47
48 def caesar_decipher_letter(letter, shift):
49 """Decipher a letter, given a shift amount
50
51 >>> caesar_decipher_letter('b', 1)
52 'a'
53 >>> caesar_decipher_letter('b', 2)
54 'z'
55 """
56 return caesar_encipher_letter(letter, -shift)
57
58 def caesar_encipher(message, shift):
59 """Encipher a message with the Caesar cipher of given shift
60
61 >>> caesar_encipher('abc', 1)
62 'bcd'
63 >>> caesar_encipher('abc', 2)
64 'cde'
65 >>> caesar_encipher('abcxyz', 2)
66 'cdezab'
67 >>> caesar_encipher('ab cx yz', 2)
68 'cd ez ab'
69 >>> caesar_encipher('Héllo World!', 2)
70 'Jgnnq Yqtnf!'
71 """
72 enciphered = [caesar_encipher_letter(l, shift) for l in message]
73 return ''.join(enciphered)
74
75 def caesar_decipher(message, shift):
76 """Decipher a message with the Caesar cipher of given shift
77
78 >>> caesar_decipher('bcd', 1)
79 'abc'
80 >>> caesar_decipher('cde', 2)
81 'abc'
82 >>> caesar_decipher('cd ez ab', 2)
83 'ab cx yz'
84 >>> caesar_decipher('Jgnnq Yqtnf!', 2)
85 'Hello World!'
86 """
87 return caesar_encipher(message, -shift)
88
89
90 if __name__ == "__main__":
91 import doctest
92 doctest.testmod()