{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Informatische Werkzeuge in den Geistes- und Sozialwissenschaften I\n", "\n", "## Hausaufgabe 7 (Reguläre Ausdrücke, 100 Punkte)\n", "\n", "**Erschienen:** 30.11.2019 \n", "**Abgabe bis:** 08.12.2019\n", "\n", "Bitte laden Sie Ihre Notebooks bis 23:59 Uhr am Abgabetag in Ihrer Übungsgruppe bei [StudOn](https://www.studon.fau.de) hoch.\n", "\n", "Wenn Ihnen einige der hier verwendeten Konzepte unbekannt sind oder Sie nicht wissen, wie Sie fortfahren sollen, können Sie die [Vorlesungsunterlagen](https://kwarc.info/teaching/IWGS/) zu Rate ziehen oder jederzeit Fragen im [Forum](https://www.studon.fau.de/studon/ilias.php?ref_id=2719645&cmdClass=ilobjforumgui&cmdNode=yf:os&baseClass=ilRepositoryGUI) stellen, im [Tutorium](https://univis.fau.de/form?__s=2&dsc=anew/lecture_view&lvs=forsch/fokomp/izdihu/inform&anonymous=1&dir=tech/IMMD/pkosy&founds=forsch/fokomp/izdihu/inform&nosearch=1&ref=pande&sem=2019w&__e=190) nachfragen, oder Ihrem Tutor eine Mail schreiben." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In dieser Übung werden wir uns weiter mit regulären Ausdrücken (= Regular Expression = RegEx) auseinander setzen. Um diese in Python überhaupt benutzen zu können ist es wichtig, dass Sie daran die `re`-Bibliothek mit folgendem Ausdruck zu importieren:\n", "```python\n", "import re\n", "```\n", "In diesem Notebook ist das in der nächsten Zelle schon für Sie getan, führen Sie diese also auf jeden Fall aus, bevor Sie beginnen. Außerdem stellen wir Ihnen eine Funktion `validMatch(r,s)` zur Verfügung. Mit dieser können Sie einfach und unkompliziert überprüfen, ob ein String `s` _komplett_ von einem RegEx `r` gematcht wird. Machen Sie sich auch mit dieser Funktion und den dazugehörigen Test vertraut." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Match!\n", "Kein Match!\n", "-----\n", "Match!\n", "Kein Match!\n", "Kein Match!\n" ] } ], "source": [ "import re\n", "\n", "# validMatch gibt nur \"True\" zurück, falls\n", "# der _gesamte_ String auf den RegEx passt.\n", "def validMatch(regex, string):\n", " if re.fullmatch(regex,string) is None:\n", " print(\"Kein Match!\")\n", " else:\n", " print(\"Match!\")\n", " \n", "validMatch(\"e+se+l\", \"eeeseeel\") # Passt.\n", "validMatch(\"e+se+l\", \"weeeseeel\") # Passt nicht, String startet anders.\n", "print(\"-----\")\n", "validMatch(\"mat.*\", \"matterhorn\") # Passt.\n", "validMatch(\"mat.\", \"matterhorn\") # Passt nicht, String geht weiter.\n", "validMatch(\"mat.\", \"cats\") # Passt nicht, String startet anders." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Aufgabe 7.1 (RegEx für einfache Postadressen, 15 Punkte)\n", "\n", "Der größte Vorteil von regulären Ausdrücken ist, dass sich damit sehr leicht große Mengen Text auf bestimmte Muster durchsuchen lassen können. Dieser Umstand kann besonders in Textwissenschaften zum Tragen kommen. Eines der bekanntesten Beispiele im Internet für dieses Phänomen ist jedoch folgender **xkcd** Webcomic:\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir werden in dieser Aufgabe versuchen, ein ähnliches Problem zu lösen (allerdings werden wir als Programmiersprache Python statt Perl verwenden). Wir werden nach Ausdrücken suchen, die aus einer (fünfstelligen) Postleitzahl und einem einfachen deutschen Ortsnamen bestehen.\n", "\n", "**Aufgabe:** Weisen Sie der Variable `address` einen regulären Ausdruck zu, der auf Strings passt, die aus genau fünf Ziffern (PLZ) gefolgt von einem Leerzeichen, gefolgt von einem Ortsnahmen bestehen. Ein Ortsname ist für unsere Zwecke ein Wort mit genau einem großen Buchstaben am Anfang, gefolgt von mindestens einem kleinen Buchstaben. Der Einfachheit halber können Sie für diese Aufgabe annehmen, dass Ortsnamen niemals länger als 20 Zeichen sind ([Gegenbeispiel](https://de.wikipedia.org/wiki/Hellschen-Heringsand-Unterschaar)), keine Interpunktion, Sonderzeichen oder Leerzeichen enthalten ([Gegenbeispiel](https://de.wikipedia.org/wiki/St._Georgen_im_Schwarzwald)). Die Buchstaben `Ä`, `Ö`, `Ü` und `ß` kommen jedoch vor, die ersten drei potentiell auch am Anfang des Wortes.\n", "\n", "_Testen Sie Ihren RegEx mit den Tests in der übernächsten Codezelle._" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# Ihr Code hier! (Doppelklick zum Editieren, Shift + Enter um die Zelle auszuführen)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Match!\n", "Match!\n", "Match!\n", "-----\n", "Kein Match!\n", "Kein Match!\n", "Kein Match!\n", "Kein Match!\n" ] } ], "source": [ "# Tests zur Überprüfung Ihres RegEx.\n", "\n", "#validMatch(address,\"91058 Erlangen\") # Sollte übereinstimmen.\n", "#validMatch(address,\"33649 Bielefeld\") # Sollte übereinstimmen.\n", "#validMatch(address,\"85716 Unterschleißheim\") # Sollte übereinstimmen\n", "print(\"-----\")\n", "#validMatch(address,\"IWGS macht Spaß!\") # Sollte _nicht_ übereinstimmen.\n", "#validMatch(address,\"33649 BIELEFELD\") # Sollte _nicht_ übereinstimmen.\n", "#validMatch(address,\"Erlangen 91058\") # Sollte _nicht_ übereinstimmen.\n", "#validMatch(address,\"123456789 Entenhausen\") # Sollte _nicht_ übereinstimmen." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Aufgabe 7.2 (RegEx für einfache Email-Adressen, 15 Punkte)\n", "\n", "Nachdem nun Ädgar Ägyptologe allen seinen Kolleg\\*innen im boomenden Wirtschaftszweig der angewandten Ägyptologie von Ihren Fähigkeiten erzählt hat, wird Ihr E-Mail-Postfach in den letzten Tagen geradezu überschwämmt von Anfragen nach kostenloser Arbeit oder Arbeit für \"Reichweite\". Sie beschließen, eine strengere SPAM-Filter-Regel einzuführen, um sich diesen Andrang zu ersparen. Allerdings wollen Sie keine für Ihr Studium wichtigen E-Mails aus Versehen aussortieren. Sie beschließen also, dass Sie in Zukunft nur noch Emails von anderen Uni-Accounts annehmen werden.\n", "\n", "**Aufgabe:** Schreiben Sie einen regulären Ausdruck (und weisen Sie ihn der Variable `email` zu), der nur auf Email-Addressen passt, die nach dem Muster `vorname.nachname@fau.de` oder `vorname.vorname.nachname@fau.de` aufgebaut sind. Vor- und Nachnamen bestehen aus Buchstaben.\n", "\n", "Sie können der Einfachheit halber für diese Zwecke das Kürzel `\\w` (identisch zum Ausdruck `[0-9a-zA-Z_]`) benutzen, auch wenn in tatsächlichen Namen selten Zahlen oder Unterstriche vorkommen. Sonderzeichen wie `[ÄäÖöÜüßéè...]` werden von `\\w` nicht getroffen, diese sind allerdings in Email-Addressen unüblich, da diese klassischerweise auf den [ASCII](https://de.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange)-Zeichensatz beschränkt sind.\n", "\n", "_Testen Sie Ihren RegEx mit den Tests in der übernächsten Codezelle._" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "# Ihr Code hier! (Doppelklick zum Editieren, Shift + Enter um die Zelle auszuführen)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Match!\n", "Match!\n", "Match!\n", "-----\n", "Kein Match!\n", "Kein Match!\n", "Kein Match!\n" ] } ], "source": [ "# Tests zur Überprüfung Ihres RegEx.\n", "\n", "#validMatch(email, \"philipp.kurth@fau.de\") # Sollte übereinstimmen.\n", "#validMatch(email, \"jonas.betzendahl@fau.de\") # Sollte übereinstimmen.\n", "#validMatch(email, \"michael.erfunden.kohlhase@fau.de\") # Sollte übereinstimmen.\n", "print(\"-----\")\n", "#validMatch(email, \"philipp.kurth@fau#de\") # Sollte _nicht_ übereinstimmen.\n", "#validMatch(email, \"jonas.betzendahl@gmail.com\") # Sollte _nicht_ übereinstimmen.\n", "#validMatch(email, \"michael.mehr.als.zwei.vornamen.kohlhase@fau.de\") # Sollte _nicht_ übereinstimmen." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Aufgabe 7.3 (RegEx Gruppen, 40 Punkte)\n", "\n", "In der nächsten Codezelle finden Sie in der Variable `gizmodo_heat` einen adaptierten Auszug aus [\"Brutal Heat Wave Breaks Temperature Records Across Europe\"](https://earther.gizmodo.com/brutal-heat-wave-breaks-temperature-records-across-euro-1836695482), einem Artikel über die Hitzewelle im Sommer diesen Jahres. Darin kommen mehrere Angaben zu Temperaturen vor, welche allerdings alle in Grad Fahrenheit (\"degrees Fahrenheit\") gegeben sind, da der Artikel für ein US-Amerikanisches Publikum geschrieben wurde. Im Rahmen dieser Aufgabe werden Sie diese Temperaturangaben für besseres Verständnis in Europa in Grad Celsius umrechnen.\n", "\n", "Zur Erinnerung, die Formel zur Umrechnung ist wie folgt: $[°C] = ([°F] - 32) \\cdot \\frac{5}{9}$.\n", "\n", "Dabei ist wichtig zu bemerken, dass im Text auch Zahlen vorkommen, die keine Temperaturangaben darstellen (z.B. \"2015\" oder \"1947\"). Hier können _Gruppen_ in RegExes hilfreich werden. Eine _Gruppe_ in einem regulären Ausdruck ist ein Teil des Ausdrucks, der in runde Klammern gestellt wird. Wenn nun dieser RegEx für Suche im Text benutzt wird, wird nach wie vor auf den gesamten regulären Ausdruck abgeglichen, aber wenn am Ende ein Ergebnis produziert wird, werden nur die Teile des Ausdrucks, die in Gruppen standen, zurück gegeben.\n", "\n", "Unser Beispiel dafür wird der RegEx `(.)at` sein. Dieser findet alle drei Zeichen langen Teilstrings, die auf `\"at\"` enden (`.` ist der RegEx für ein beliebiges Zeichen). Da wir aber eine Gruppe um das erste Zeichen gesetzt haben, wird nur dieses in der Ergebnisliste zu finden sein.\n", "\n", "_Beispiel:_\n", "```python\n", "# Ohne Gruppe.\n", "re.findall(\".at\", \"The cat with the hat on the mat wants a pat.\") == ['cat','hat','mat','pat']\n", "\n", "# Mit Gruppe.\n", "re.findall(\"(.)at\", \"The cat with the hat on the mat wants a pat.\") == ['c','h','m','p']\n", "```\n", "\n", "Basierend auf der Art und Weise, wie die meisten Programmiersprachen, darunter auch Python, mit Kommazahlen umgehen, kann es zu geringen Ungenauigkeiten kommen. Wir werden hier nicht genauer auf die technischen Details eingehen, aber wir wollen gerne lernen, Zahlen wie `1.5000000000000002` in den Ausgaben unserer Programme zu vermeiden. Eine Möglichkeit dafür ist die Funktion `round(z,n)`, die eine Zahl `z` auf `n` Nachkommastellen rundet.\n", "\n", "_Beispiel:_\n", "```python\n", "# 1.5000000000000002\n", "print(3.2-1.7)\n", "\n", "#1.5\n", "print(round(3.2-1.7,2))\n", "```\n", "\n", "**Aufgabe:** Schreiben Sie ein Python-Programm, das den gegebenen Text mit einem regulären Ausdruck nach allen Temperaturangaben durchsucht. Achten Sie darauf, dass Ihr Ausdruck tatsächlich nur Temperaturen in Grad Fahrenheit trifft und keine Datumsangaben. Benutzen Sie dafür eine _Gruppe_ in Ihrem Ausdruck. Konvertieren Sie alle Treffer in Zahlen und rechnen Sie diese in Grad Celsius um und geben Sie die Ergebnisse (auf zwei Nachkommastellen gerundet) aus. " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "# Text adapted from \"Brutal Heat Wave Breaks Temperature Records Across Europe\"\n", "# https://earther.gizmodo.com/brutal-heat-wave-breaks-temperature-records-across-euro-1836695482\n", "gizmodo_heat = \"\"\"Germany saw its temperature break Wednesday as Geilenkirchen, a town in the northwestern corner \n", " part of the country near the Netherlands border, reached 104.9 degrees Fahrenheit. The previous\n", " record from July 5, 2015, was 104.5 degrees Fahrenheit, according to the DWD German weather\n", " service.\n", "\n", " Next door in the Netherlands, record temperatures broke, too. On Thursday, the municipality of\n", " Gilze en Rijen reached 104.7 degrees Fahrenheit, shooting past the previous record of\n", " 104 degrees Fahrenheit, the Royal Netherlands Meteorological Institute reports. That previous\n", " record was set just a day earlier.\n", "\n", " In France, temperatures have been breaking nonstop throughout cities Thursday, according to the\n", " French meteorological service. Paris saw its mercury reach 108.6 degrees Fahrenheit; its\n", " previous record was 104.7 degrees Fahrenheit set in 1947. Lille in northern France near the\n", " Belgium border broke its record — 99.7 degrees Fahrenheit from just last year — at\n", " 104.9 degrees Fahrenheit. Officials are concerned the heat could cause the collapse of the\n", " fragile Notre Dame Cathedral, which almost burned to the ground in April.\"\"\"" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# Ihr Code hier! (Doppelklick zum Editieren, Shift + Enter um die Zelle auszuführen)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Aufgabe 7.4 (RegEx Kreuzworträtsel, 30 Punkte)\n", "\n", "Nachdem Sie Ihrer guten Freundin, Beatrice Beispiel, letzte Woche bereits mit ihren Problemen mit regulären Ausdrücken geholfen haben, kommt sie diese Woche erneut auf sie zurück. Dieses Mal nicht mit einer Bitte um Hilfe, sondern mit einer lustigen Freizeitbeschäftigung, die sie zwei zusammen genießen können, so sagt sie. Sie stutzen kurz, weil Sie sich innerlich schon auf mehr Arbeit vorbereitet hatten, aber lassen sich schnell von Freizeit überzeugen.\n", "\n", "Beatrice stellt Ihnen [RegEx-Kreuzworträtsel](https://regexcrossword.com/) vor. Diese funktionieren ähnlich wie normale Kreuzworträtsel, mit dem Unterschied, dass die Hinweise keine Umschreibungen des Wortes sind, sondern reguläre Ausdrücke, die auf die Einträge in der jeweiligen Zeile oder Spalte matchen (Wenn diese Regeln unklar erscheinen, können Sie [hier](https://regexcrossword.com/howtoplay) nachlesen).\n", "\n", "Ein paar einfache Beispiele hat Beatrice schon selbst ausgefüllt:\n", "\n", "_Beispiel 1:_\n", "\n", "| | **A+** |\n", "|:--------:|:------:|\n", "| **A\\|B** | A |\n", "\n", "_Beispiel 2:_\n", "\n", "| | **B\\*** |\n", "|:---------:|:-------:|\n", "| **[ABC]** | B |\n", "| **A\\|B** | B |\n", "\n", "_Beispiel 3:_\n", "\n", "| | **A?** | **B\\*** | **C?E?D?** |\n", "|:----------:|:--------:|:--------:|:----------:|\n", "| **[CAB]+** | A | B | C |\n", "\n", "Sie beschleicht das nagende Gefühl, dass Beatrice diese Kreuzworträtsel doch nicht nur zur Unterhaltung mitgebracht hat. Statt aber die direkte Frage zu stellen, ob sie zufällig in naher Zukunft für einen ihrer Kurse ausgefüllte RegEx-Kreuzworträtsel abgeben muss, geben Sie sich der Aufgabe hin. Immerhin sieht es durchaus spaßig aus." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Aufgabe:** Füllen Sie die folgenden RegEx-Kreuzworträtseltabellen so aus, dass alle an den Rändern gegebenen RegExe erfüllt werden. In jeder Zelle wird nur ein Zeichen erwartet.\n", "\n", "_Rätsel 1 (Beatles):_\n", "\n", "| | **[^SPEAK]+** | **EP\\|IP\\|IF** |\n", "| --------------: | :-----------: | :------------: |\n", "| **HE\\|LL\\|O+** | | |\n", "| **[PLEASE]+** | | |\n", "\n", "_Rätsel 2 (Ghost):_\n", "\n", "| | **[COBRA]+** | **(AB\\|O\\|OR)+** |\n", "| --------------: | :----------: | :--------------: |\n", "| **BO\\|QR\\|LL** | | |\n", "| **[^ABRC]+** | | |\n", "\n", "_Rätsel 3 (Symbolism):_\n", "\n", "| | **.?.+** | **.+** |\n", "| ---------: | :-------: | :-----: |\n", "| **[\\*]+** | | |\n", "| **/+** | | |" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.0" } }, "nbformat": 4, "nbformat_minor": 4 }