"git@scm.cms.hu-berlin.de:iqb/verona-modules-aspect.git" did not exist on "0dba1d02eeaf6d68947341704f5615e1e39e5870"
Newer
Older
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Seminar Problemorientierte Programmierung\n",
"\n",
"## 3 Extra: Reguläre Ausdrücke\n",
"\n",
"Dieses Kapitel taucht nicht im englischen Python-Kurs auf und wird separat gepflegt.\n",
"\n",
"In der Praxis können wir reguläre Ausdrücke nutzen, um in Texten zu suchen und Muster zu entdecken. Python bietet uns im `re`-Modul (re = Regular Expression = Regulärer Ausdruck) viele Funktionen an, um mit regulären Ausdrücken zu arbeiten. \n",
"\n",
"Es gibt dabei zwei \"Dimensionen\" an denen wir uns \"entlanghangeln\" müssen: die Funktionen, die vom `re`-Modul bereitgestellt werden und die regulären Ausdrücke selber, die komplex werden können. Wir beginnen zunächst mit nur einer Funktion und werden Stück für Stück komplexere Ausdrücke kennenlernen. Danach schauen wir uns weitere Funktionen an. \n",
"\n",
"### Ihre Lernziele\n",
"\n",
"Beschreiben Sie in 2-3 Stichpunkten kurz was Sie im Seminar heute lernen wollen. Klicken Sie dazu doppelt auf diesen Text und bearbeiten Sie dann den Text:\n",
"\n",
"- \n",
"- \n",
"- \n",
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
"\n",
"In einer Datei alle E-Mail-Adressen extrahieren geht recht einfach:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"\n",
"def find_in_file(pattern, file):\n",
" reg_pattern = re.compile(pattern)\n",
" for line in file:\n",
" for found in reg_pattern.findall(line):\n",
" print(found[0])\n",
"\n",
"find_in_file(r\"([a-zA-Z0-9-!#$%&'*+-/=?^_`{|}~]+@([A-Za-z0-9-]+\\.)+[a-zA-Z]{2,})\", open(\"test.txt\", \"rt\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.1 Einfache Suche\n",
"\n",
"Wir können mit der Funktion `findall` alle Teilzeichenketten in einer Zeichenkette finden, die auf ein gegebenes Muster (in Form eines regulären Ausdrucks) passen. Die Funktion erwartet zwei Argumente: einen regulären Ausdruck und die Zeichenkette, die durchsucht werden soll: "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"re.findall(r'f[a-z]*', 'which foot or hand fell fastest')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"1. In der ersten Zeile wird das `re`-Modul importiert. Das muss einmal am Anfang unseres Programms passieren. Hier im Jupyter-Notebook reicht es, wenn das Modul in einem Block importiert wird - sobald der Block ausgeführt wurde, kann es in allen folgenden Blöcken verwendet werden.\n",
"2. In der nächsten Zeile wird - mittels der Punkt-Notation - die `findall`-Funktion im `re`-Modul aufgerufen.\n",
"3. Der Funktion werden zwei Argumente übergeben: `r'f[a-z]*'` und `'which foot or hand fell fastest'`.\n",
"4. Das erste Argument ist ein regulärer Ausdruck. Reguläre Ausdrücke werden in Hochkommata `''` eingeschlossen und beginnen mit einem `r`. \n",
"5. Das heißt, der eigentliche reguläre Ausdruck lautet `f[a-z]*`. Dieser Ausdruck beschreibt Zeichenketten, die mit einem `f` beginnen und von beliebig vielen - auch 0! - (`*`) Kleinbuchstaben (`[a-z]`) gefolgt werden. Dabei beschreibt der Ausdruck `[a-z]` in eckigen Klammern ein Zeichen, welches die Werte `a` bis `z` haben darf, das `*` dahinter besagt, dass dieses Zeichen beliebig oft wiederholt werden darf.\n",
"6. Das zweite Argument (`'which foot or hand fell fastest'`) ist die Zeichenkette, in der wir nach Teilzeichenketten suchen, die auf den übergebenen regulären Ausdruck passen.\n",
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"\n",
"Das Ergebnis des Aufrufs von `findall` ist eine Liste der Teilzeichenketten, die auf das Muster passen - in unserem Beispiel sind das die Zeichenketten `foot`, `fell` und `fastest`. \n",
"\n",
"Probieren Sie es hier selber aus:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"regaus = r'f[a-z]*'\n",
"text = input(\"Geben Sie eine Zeichenkette zum Testen ein:\")\n",
"ergebnis = re.findall(regaus, text)\n",
"if ergebnis:\n",
" print(\"Es wurden folgende Teilzeichenketten erkannt:\", ergebnis)\n",
"else:\n",
" print(\"Leider wurde nichts erkannt, probieren Sie es noch einmal.\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ändern Sie den regulären Ausdruck im folgenden Beispiel, so dass alle Wörter, die mit einem `b` beginnen ausgegeben werden: "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"re.findall(r'b', 'Wir bauten und bohrten bis das Haus fertig war.')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Die Ausgabe sollte so aussehen:\n",
"```\n",
"['bauten', 'bohrten', 'bis']\n",
"```\n",
"Ändern Sie den regulären Ausdruck, so dass jetzt nur Wörter ausgegeben werden, die mit einem `b` beginnen und mit einem `n` enden. Die Ausgabe sollte dann so aussehen:\n",
"```\n",
"['bauten', 'bohrten']\n",
"```\n",
"\n",
"Welche Probleme sind bei Ihren Versuchen aufgetreten?\n",
"- \n",
"- \n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.2 Schritt für Schritt: ein beliebiges Zeichen\n",
"\n",
"Der Punkt `.` steht für ein beliebiges Zeichen: "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"re.findall(r'a.', \"Am Anfang aßen wir alle Manna und Kartoffeln\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Im Satz `Am Anfang aßen wir alle Kartoffeln.` gibt es genau sechs Vorkommen von einem kleinen `a` mit einem Zeichen dahinter. Wie wir sehen, wird auch das `a` am Ende von `Manna`, welches von einem Leerzeichen gefolgt ist, erkannt. Das liegt daran, dass der Punkt für wirklich jedes Zeichen (auch das Leerzeichen) steht. Die zwei Zeichenketten `Am` und `An` werden nicht erkannt, da sie ein großes `A` enthalten, wir aber nach einem kleinen gesucht haben."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Sie kennen jetzt eine Funktion, um reguläre Ausdrücke in Python anzuwenden und damit Texte zu durchsuchen. Weitere Funktionen ermöglichen die Extraktion und das Ersetzen von Teilzeichenketten in Texten. Bevor wir diese Funktionen kennenlernen, ist es praktisch, mit regulären Ausdrücken vertraut zu werden. Eine sehr gute interaktive Übungsseite dazu finden Sie [hier](https://regexone.com/lesson/introduction_abcs). Arbeiten Sie diese Seite gemeinsam Schritt für Schritt durch. Schrecken Sie nicht vor dem englischen Text zurück - ich helfe Ihnen bei Fragen gerne weiter.\n",
"\n",
"Es gibt noch viele andere gute Tutorials zu regulären Ausdrücken, z.B. [hier](https://ryanstutorials.net/regular-expressions-tutorial/) oder [hier](https://www.python-kurs.eu/re.php). Sie können auch eine dieser Anleitungen durcharbeiten, wenn Sie damit besser zurechtkommen."
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3.4 weitere nützliche Funktionen des `re`-Moduls\n",
"\n",
"Sie haben in den Tutorials einige regulären Ausdrücke kennengelernt. Nun können wir weitere Funktionen des `re`-Moduls benutzen. Im Folgenden werden mehrere Funktionen vorgestellt. Anschließend können Sie diese in Übungen testen.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 3.4.1 Suchen und Matchen \n",
"\n",
"Die Funktion `findall(regex,string)` haben sie schon kennengelernt:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"re.findall(r'f[a-z]*', 'which foot or hand fell fastest')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Zudem gibt es eine Funktion `search(regex,string)`. Die Argumente sind diesselben wie bei `findall`.\n",
"Diese Funktion durchsucht eine Zeichenkette *string* nach dem Vorkommen eines Teilstrings, der auf den regulären Ausdruck *regex* passt. Der erste gefundene Teilstring wird zurückgeliefert. Die Rückgabe ist ein sogennantes *match-Objekt*."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import re\n",
"object1 = re.search(r'f[a-z]*', 'which foot or hand fell fastest')\n",
"\n",
"object2 = re.search(r'f[a-z]*', 'The regex did not match anything.')\n",
"\n",
"print(object1,\"\\n\",object2)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ein *match-Objekt* enthält die Methoden `group()`, `span()`, `start()` und `end()`, die man im folgenden Beispiel im selbsterklärenden Einsatz sieht: "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"object1 = re.search(r'f[a-z]*', 'which foot or hand fell fastest')\n",
"print(object1.group())\n",
"print(object1.span())\n",
"print(object1.start())\n",
"print(object1.end())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Es gibt zuletzt noch eine dritte Funktion `match(regex,string)`. Diese Funktion checkt, ob ein Teilstring, der auf den regulären Ausdruck *regex* passt, am Anfang der Zeichenkette *string* vorkommt, Die Rückgabe ist wieder ein *match-Objekt*."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"object1 = re.match(r'f[a-z]*', 'foot or hand fell fastest')\n",
"object2 = re.match(r'f[a-z]*', 'which foot or hand fell fastest')\n",
"print(object2)\n",
"print(object1)\n",
"print(object1.group())\n",
"print(object1.span())\n",
"print(object1.start())\n",
"print(object1.end())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 3.4.1 Übung:\n",
"\n",
"Denken Sie sich eine Zeichenkette und einen regulären Ausdruck aus, die die Unterschiede der drei kennengelernten Funktionen wiedergibt. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 3.4.2 Ersetzen "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Das `re`-Modul stellt nicht nur Funktionen zum Durchsuchen von Zeichenketten zur Verfügung. Mit der Funktion `re.sub(regex, replacement, string)` kann man Teilstrings ersetzen. Jede Übereinstimmung des regulären Ausdrucks *regex* in der Zeichenkette *string* wird durch die Zeichenkette *replacement* ersetzt."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"re.sub(r'f[a-z]*', 'beer', 'which foot or hand fell fastest')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 3.4.3 Kompilieren\n",
"\n",
"Wenn man bestimmte reguläre Ausdrücke mehrmals benutzen möchte, kann man die Funktion `compile(regex)` benutzen. Diese Funktion kompiliert einen regulären Ausdruck *regex* in eine regex-Objekt. Dieses kann man dann für weitere Funktionen nutzen."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"regex_1 = re.compile(r'f[a-z]*')\n",
"\n",
"print(regex_1.findall('which foot or hand fell fastest'))\n",
"\n",
"print(regex_1.search('which foot or hand fell fastest'))\n",
"\n",
"print(regex_1.match('which foot or hand fell fastest'))\n",
"\n",
"print(regex_1.sub('beer','which foot or hand fell fastest'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Aufgaben\n",
"\n",
"#### Aufgabe 1\n",
"Schreiben Sie eine Funktion, die eine Zeichenkette als Parameter entgegennimmt und überprüft, ob die Zeichenkette nur Kleinbuchstaben und Zahlen enthält. \n",
"Benutzen Sie reguläre Ausdrücke und die obigen Funktionen."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Aufgabe 2\n",
"\n",
"Schreiben Sie eine Funktion, die eine Zeichenkette als Parameter entgegennimmt und überprüft, ob die Zeichenkette einen Teilstring enthält, der aus einem \"a\" und nachfolgend aus mindestens einem \"b\" besteht. (z.B. \"abb\", \"abbbbb\", \"abbbbbbbbbbbbbbbb\"). \n",
"Benutzen Sie reguläre Ausdrücke und die obigen Funktionen.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Aufgabe 3\n",
"\n",
"Schreiben Sie eine Funktion, die eine Zeichenkette als Parameter entgegennimmt und alle darin enthaltenen Leerzeichen durch ein Minus ersetzt. \n",
"Benutzen Sie reguläre Ausdrücke und die obigen Funktionen."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### Aufgabe 4\n",
"\n",
"Schreiben Sie eine Funktion, die eine Zeichenkette *s* und eine natürliche Zahl *n* als Parameter entgegennimmt und alle Wörter der Länge n aus der Zeichenkette *s* entfernt. \n",
"Benutzen Sie reguläre Ausdrücke und die obigen Funktionen."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" Speichern Sie dieses Notebook so, dass Ihre Änderungen nicht verlorengehen (nicht auf einem Pool-Rechner). Klicken Sie dazu oben links auf das Disketten-Icon und nutzen Sie beispielsweise einen USB-Stick, E-Mail, Google Drive, Dropbox oder Ihre [HU-Box](https://box.hu-berlin.de/). "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"Herzlichen Glückwunsch! Sie haben das 3. Kapitel geschafft. Weiter geht es in [4: Fallstudie: Schnittstellenentwurf](seminar04.ipynb)."
]
}
],
"metadata": {
"language_info": {
"name": "python",
"pygments_lexer": "ipython3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}