f45a166ca80d71f37605364c4dac44c9e43925d1
[cipher-training.git] / slides / caesar-encipher.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Caesar cipher</title>
5 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
6 <style type="text/css">
7 /* Slideshow styles */
8 body {
9 font-size: 20px;
10 }
11 h1, h2, h3 {
12 font-weight: 400;
13 margin-bottom: 0;
14 }
15 h1 { font-size: 3em; }
16 h2 { font-size: 2em; }
17 h3 { font-size: 1.6em; }
18 a, a > code {
19 text-decoration: none;
20 }
21 code {
22 -moz-border-radius: 5px;
23 -web-border-radius: 5px;
24 background: #e7e8e2;
25 border-radius: 5px;
26 font-size: 16px;
27 }
28 .plaintext {
29 background: #272822;
30 color: #80ff80;
31 text-shadow: 0 0 20px #333;
32 padding: 2px 5px;
33 }
34 .ciphertext {
35 background: #272822;
36 color: #ff6666;
37 text-shadow: 0 0 20px #333;
38 padding: 2px 5px;
39 }
40 </style>
41 </head>
42 <body>
43 <textarea id="source">
44
45 # Caesar ciphers
46
47 ![centre-aligned Caesar wheel](caesarwheel1.gif)
48
49 Letter-by-letter enciphering
50
51 ---
52
53 # Enciphering and deciphering
54
55 ## Arithmetic on letters
56
57 Convert .plaintext[letter] → .plaintext[number] →
58 .ciphertext[number] → .ciphertext[letter]
59
60 Functions you will need
61
62 ```python
63 ord()
64
65 chr()
66
67 %
68 ```
69
70 * What are good test cases?
71
72 ---
73
74 # The [string module](http://docs.python.org/3.3/library/string.html) is your friend
75
76 ```python
77 import string
78
79 string.ascii_letters
80 string.ascii_lowercase
81 string.ascii_uppercase
82 string.digits
83 string.punctuation
84 ```
85
86 ---
87 # DRY and YAGNI
88
89 Is your code DRY?
90
91 ---
92
93 # Doctest
94
95 * Why document?
96 * Why test?
97
98 ```python
99 def caesar_encipher_letter(letter, shift):
100 """Encipher a letter, given a shift amount
101
102 >>> caesar_encipher_letter('a', 1)
103 'b'
104 """
105 if letter in string.ascii_letters:
106 .
107 .
108 .
109 ```
110
111 ---
112
113 # The magic doctest incantation
114
115 ```python
116 if __name__ == "__main__":
117 import doctest
118 doctest.testmod()
119 ```
120
121 ---
122
123 # Accents
124
125 ```python
126 >>> caesar_encipher_letter('é', 1)
127 ```
128 What does it produce?
129
130 What should it produce?
131
132 ## Unicode, combining codepoints, and normal forms
133
134 Text encodings will bite you when you least expect it.
135
136 * urlencoding is the other pain point.
137
138 ---
139
140 # Five minutes on StackOverflow later...
141
142 ```python
143 def unaccent(text):
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.
147
148 >>> unaccent('hello')
149 'hello'
150 >>> unaccent('HELLO')
151 'HELLO'
152 >>> unaccent('héllo')
153 'hello'
154 >>> unaccent('héllö')
155 'hello'
156 >>> unaccent('HÉLLÖ')
157 'HELLO'
158 """
159 return unicodedata.normalize('NFKD', text).\
160 encode('ascii', 'ignore').\
161 decode('utf-8')
162 ```
163
164 ---
165
166 # Doing all the letters
167
168 ## Test-first developement
169
170 1. Write the tests.
171 * They will fail. There is no code.
172 2. Write code until the tests pass.
173 3. Refactor.
174
175 ---
176
177 # Doing all the letters
178
179 ## Abysmal
180
181 ```python
182 ciphertext = ''
183 for i in range(len(plaintext)):
184 ciphertext += caesar_encipher_letter(plaintext[i], key)
185 ```
186
187 ---
188
189 # Doing all the letters
190
191 ## Bad
192
193 ```python
194 ciphertext = ''
195 for p in plaintext:
196 ciphertext += caesar_encipher_letter(p, key)
197 ```
198
199 ...but easily generalisable
200
201 ---
202
203 # Doing all the letters
204
205 ## Good (but unPythonic)
206
207 ```python
208 ciphertext = map(lambda p: caesar_encipher_letter(p, key), plaintext)
209 ```
210
211 ---
212
213 # Doing all the letters
214
215 ## Best
216
217 ```python
218 ciphertext = [caesar_encipher_letter(p, key) for p in plaintext]
219 ```
220 ---
221
222 # Not all iterables are equal
223
224 ```python
225 ''.join()
226 ```
227
228 </textarea>
229 <script src="http://gnab.github.io/remark/downloads/remark-0.6.0.min.js" type="text/javascript">
230 </script>
231 <script type="text/javascript">
232 var slideshow = remark.create({ ratio: "16:9" });
233 </script>
234 </body>
235 </html>