4 <title>Caesar cipher
</title>
5 <meta http-equiv=
"Content-Type" content=
"text/html; charset=UTF-8"/>
6 <style type=
"text/css">
15 h1 { font-size:
3em; }
16 h2 { font-size:
2em; }
17 h3 { font-size:
1.6em; }
19 text-decoration: none;
22 -moz-border-radius:
5px;
23 -web-border-radius:
5px;
31 text-shadow:
0 0 20px #
333;
37 text-shadow:
0 0 20px #
333;
43 <textarea id=
"source">
47 ![centre-aligned Caesar wheel](caesarwheel1.gif)
49 Letter-by-letter enciphering
53 # Enciphering and deciphering
55 ## Arithmetic on letters
57 Convert .plaintext[letter] → .plaintext[number] →
58 .ciphertext[number] → .ciphertext[letter]
60 Functions you will need
70 * What are good test cases?
74 # The [string module](http://docs.python.org/
3.3/library/string.html) is your friend
80 string.ascii_lowercase
81 string.ascii_uppercase
99 def caesar_encipher_letter(letter, shift):
100 """Encipher a letter, given a shift amount
102 >>> caesar_encipher_letter('a', 1)
105 if letter in string.ascii_letters:
113 # The magic doctest incantation
116 if __name__ ==
"__main__":
126 >>> caesar_encipher_letter('é',
1)
128 What does it produce?
130 What should it produce?
132 ## Unicode, combining codepoints, and normal forms
134 Text encodings will bite you when you least expect it.
136 * urlencoding is the other pain point.
140 # Five minutes on StackOverflow later...
144 """Remove all accents from letters.
145 It does this by converting the unicode string to decomposed compatibility
146 form, dropping all the combining accents, then re-encoding the bytes.
148 >>> unaccent('hello')
150 >>> unaccent('HELLO')
152 >>> unaccent('héllo')
154 >>> unaccent('héllö')
156 >>> unaccent('HÉLLÖ')
159 return unicodedata.normalize('NFKD', text).\
160 encode('ascii', 'ignore').\
166 # Doing all the letters
168 ## Test-first developement
171 * They will fail. There is no code.
172 2. Write code until the tests pass.
177 # Doing all the letters
183 for i in range(len(plaintext)):
184 ciphertext += caesar_encipher_letter(plaintext[i], key)
189 # Doing all the letters
196 ciphertext += caesar_encipher_letter(p, key)
199 ...but easily generalisable
203 # Doing all the letters
205 ## Good (but unPythonic)
208 ciphertext = map(lambda p: caesar_encipher_letter(p, key), plaintext)
213 # Doing all the letters
218 ciphertext = [caesar_encipher_letter(p, key) for p in plaintext]
222 # Not all iterables are equal
229 <script src=
"http://gnab.github.io/remark/downloads/remark-0.6.0.min.js" type=
"text/javascript">
231 <script type=
"text/javascript">
232 var slideshow = remark.create({ ratio:
"16:9" });