Programmieren Wintersemester 2014/15 Software-Design und Qualität (SDQ) https://sdqweb.ipd.kit.edu/wiki/ Programmieren Prof. Dr. Ralf H. Reussner · Kiana Rostami · Philipp Merkle Ausgabe: 20.01.2015 18:00 Übungsblatt 6 Abgabe: 03.02.2015 13:00 Allgemeine Hinweise 1 • Achten Sie darauf nicht zu lange Zeilen, Methoden und Dateien zu erstellen • Programmcode muss in englischer Sprache verfasst sein • Kommentieren Sie Ihren Code angemessen: So viel wie nötig, so wenig wie möglich • Wählen Sie geeignete Sichtbarkeiten für Ihre Klassen, Methoden und Attribute • Verwenden Sie keine Klassen der Java-Bibliotheken ausgenommen Klassen der Pakete java.io und java.lang, java.util. 1 • Achten Sie auf fehlerfrei kompilierenden Programmcode • Halten Sie alle Whitespace-Regeln ein • Halten Sie die Regeln zu Variablen-, Methoden und Paketbenennung ein und wählen Sie aussagekräftige 1 1 Namen 1 • Halten Sie die Regeln zu Javadoc-Dokumentation ein • Nutzen Sie nicht das default-Package • Halten Sie auch alle anderen Checkstyle-Regeln ein 1 Abgabemodalitäten Die Praktomat-Abgabe wird am Montag, den 26. Januar, freigeschaltet. Die Lösung dieses Blattes wird mehreren Java-Dateien bestehen. Laden Sie diese im Abgabezeitraum vom 26. Januar 13 Uhr - 3. Februar 13 Uhr im Praktomaten hoch. Geben Sie die Java-Klassen zu Teil A und Teil C in separaten Geben Sie Ihre Antworten zu Teil B in einer Textdatei mit dem Namen TeilB.txt *.java-Dateien ab. ab. Achten Sie unbedingt darauf, diese Dateien bei der richtigen Aufgabe hochzuladen. Für die Abgabe von Java-Klassen, die sich nicht im default-Package benden, empehlt es sich, eine .zip-Datei (alternativ .tar oder .tar.gz) hochzuladen, welche die Ordnerstruktur widerspiegelt. Checkstyle Denken Sie daran, den erweiterten Checkstyle-Regelsatz von unserer Homepage zu beziehen. Planen Sie, wie immer, ausreichend Zeit für die Abgabe ein, sollte der Praktomat Ihre Abgabe wegen einer Regelverletzung ablehnen. 1 Der Praktomat wird die Abgabe zurückweisen, falls diese Regel verletzt ist. Programmieren Wintersemester 2014/15 20.01.2015 18:00 Terminal-Hilfsklasse Terminal-Klasse2 von unserer Homepage herunter und platzieren Sie diese im Package edu.kit.informatik. Die Methode Terminal.readLine() liest eine Benutzereingabe von der Konsole und ersetzt System.in. Die Methode Terminal.printLine() schreibt eine Ausgabe auf die Konsole und ersetzt System.out. Verwenden Sie für jegliche Konsoleneingabe oder Konsolenausgabe die TerminalKlasse. Verwenden Sie in keinem Fall System.in oder System.out. Laden Sie die Fehlermeldungen werden ebenso (ausschlieÿlich) über Terminal.printLine() ausgegeben und müssen aus technischen Gründen unbedingt mit Error, beginnen. Wichtige Hinweise Werfen Sie einen Blick in die API Dokumentation des Pakets java.util 3 . In diesem Blatt werden Sie einige dieser Klassen benötigen und dadurch den Umgang mit diesen Klassen üben. Zusätzlich zu vorherigen Übungsblättern muss Ihr Programm auf alle ungültigen Benutzereingaben mit einer Fehlermeldung reagieren. Achten Sie darauf, fehlerhafte Eingaben abzufangen und keine Exception unbehandelt zu lassen. Geben Sie im Fehlerfall eine aussagekräftige Fehlermeldung beginnend mit Error, aus. A Indizierung eines Buches mittels Java API (4 Punkte) Java API anstelle eines Java API, die am besten geeignet sind. Implementieren Sie Aufgabe C des fünften Aufgabenblattes mit Hilfe von Klassen der binären Suchbaumes. Finden Sie hierzu die Klassen der A.1 Aufgabestellung In dieser Aufgabe indizieren Sie die vorkommenden Wörter eines Buches. Benutzen Sie keinesfalls Ihre imple- mentierte Baumdatenstruktur aus dem fünften Blatt. Auch in dieser Aufgabe wird beim Einfügen eines neuen Schlüssel-Wert-Paares, bei dessen Schlüssel es sich um ein Schlüssel-Duplikat handelt, nicht der alte Wert in einem existierenden Knoten überschrieben, sondern eine Liste aller Werte, die zu einem Schlüssel gehören, ge- speichert, sofern der neue Wert sich von allen bisherig gespeicherten Werten für diesen Schlüssel unterscheidet, ansonsten wird der neue Wert ignoriert. Speichern Sie jedes vorkommende Wort im übergebenen Buch als Schlüssel und als Wert die Seitennummer des Buches, auf der das Wort vorkommt. Kommt ein Wort mehrmals auf einer Seite vor, wird die Seite nur einmal gespeichert. Kommt das Wort in mehreren Seiten vor, werden alle Seiten als Wert für ein Wort gespeichert, wie im obigen Absatz beschrieben. Testen Sie Ihre Abgabe ausgiebig, bevor Sie sie im Praktomaten hochladen. A.2 Eingabe des Programms Ihr Programm akzeptiert nur einen Kommandozeilenparameter. A.2.1 Bestimmung des Buches Als einziges Kommandozeilenargument nimmt Ihr Programm einen Pfad auf eine Textdatei entgegen. Diese Textdatei beinhaltet eine vereinfachende Version eines Buches wie in Abschnitt A.2.3 beschrieben. Ihr Programm baut intern eine passende Datenstruktur mit Hilfe der Klassen der Java API für alle vorkommenden Wörter in diesem Buch, wie in Abschnitt A.1 beschrieben, auf. 2 https://sdqweb.ipd.kit.edu/lehre/WS1415-Programmieren/Terminal.java 3 http://docs.oracle.com/javase/7/docs/api/java/util/package-summary.html Seite 2 von 10 Programmieren Wintersemester 2014/15 20.01.2015 18:00 A.2.2 Interaktive Benutzerschnittstelle Ihr Programm nimmt über die Konsole mittels • Terminal.readLine() drei Arten von Befehlen entgegen. Der Befehl search key ruft die search-Methode auf und übergibt dabei key als Argument. Die Rückkey wird der form key:value auf der Konsole ausgegeben. Existiert der übergebene Schlüssel nicht, wird key:null zurückgegeben. null kommt im Buch nicht vor. Existiert gabe, d.h. der gespeicherte Wert für mehr als ein Wert zu einem Schlüssel, werden die Werte bei der Ausgabe auf der Konsole nur mit einem Komma getrennt. Die Rückgabe des Programms für beispielhaft 3 Werte zu einem Schlüssel wird wie folgt auf der Konsole ausgegeben: key:value1,value2,value3. key und value werden immer mit Doppelpunkt getrennt. Es ndet keine weitere Konsolenausgabe statt. • Der Befehl info gibt alle gespeicherten Elemente auf der Konsole aus. (Hinweis, beachten Sie strikt folgendes Ausgabeformat: Alle Paare werden der Form key:value in einer einzigen Zeile ausgegeben und sind durch ein Komma separiert. Vermeiden Sie Leerzeichen vor oder nach dem Komma. Sind mehr als ein Value zu einem key gespeichert, gilt die oben genannte Regel, d.h. alle values zu einem key werden ebenfalls mit Komma separiert.) Es ndet keine weitere Konsolenausgabe statt. • Der Befehl quit beendet das Programm. Es ndet keine Konsolenausgabe statt. Ihr Programm muss auf ungültige interaktive Benutzereingaben mit einer Fehlermeldung reagieren. Achten Sie darauf, dass alle Fehlermeldungen mit Error, anfangen. A.2.3 Aufbau des vereinfachenden Buches Die Eingabedatei enthält eine oder mehrere Zeilen. Jede Zeile beschreibt entweder die Seitennummer oder eine Zeile eines Buches. Ein Wort in einer Zeile gehört der zuletzt genannten Seitennummer. Sie können davon ausgehen, dass alle vorkommenden Buchstaben in Wörtern keine Umlaute haben. Auÿerdem kommen keine Sonderzeichen in einem Buch vor. Zudem sind alle Wörter in einem Buch klein geschrieben. Die Seiten werden immer mit dem Schlüsselwort Seite und anschlieÿend die Seitennummer ausgedruckt. Das Wort Seite kommt sonst nicht im Text vor. Nach der Seitennummer kommen keine weiteren Zeichen vor. Weiter können Sie davon ausgehen, dass die Seitennummer vom Typ Integer ist. Auÿerdem sind leere Eingabetexte nicht erlaubt. A.2.4 Beispiel eines vereinfachenden Buches Folgendes Beispiel präsentiert beispielhaft eine Programmeingabe, die vereinfachend ein Buch mit 2 Seiten repräsentiert: Seite1 lorem ipsum dolor sit amet consetetur sadipscing sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat sed diam voluptua Seite2 at vero eos et accusam et justo duo olores et ea rebum stet clita kasd gubergren no sea takimata sanctus est lorem ipsum dolor sit amet Zum Einlesen der Datei dürfen Sie den Beispielcode aus Übungsblatt 3 wiederverwenden. A.2.5 Beispielausgabe des Programms Die Suche nach Wort et erfolgt also mit: search et Seite 3 von 10 Programmieren Wintersemester 2014/15 20.01.2015 18:00 Die Ausgabe Ihres Programms lautet: et:1,2 B Diskussion (2 Punkte) Erklären Sie in eigenen Worten den Unterschied zwischen Failure, Fault und Error anhand verschiedener Beispiele innerhalb eines durchgängigen Szenarios. C Buchdatenbank (16 Punkte) In dieser Aufgabe implementieren Sie vereinfachend eine Buchdatenbank. Ihre Buchdatenbank unterstützt hauptsächlich eine Suchfunktion, die den Benutzern Ihres Programms eine exible Suche nach verschiedenen Attributwerten eines Buches anbietet. Diese gibt bei jedem gespeicherten Bucheintrag entweder true C.1 false oder aus. Annahmen In dieser Aufgabe kommen Umlaute und ÿ weder in der Eingabe noch in der Suche vor. Zudem können Sie davon ausgehen, dass das Wort unknown weder in einer Suchanfrage noch in einem Bucheintrag vorkommt. Dieses Wort ist dadurch nur für Attribute reserviert, deren Wert nicht bekannt ist. Alle Vergleiche bei allen Zeichenketten in dieser Aufgabe erfolgen ohne Beachtung der Klein- oder Groÿschreibung. C.2 Bücher Implementieren Sie eine Buchdatenbank mit Hilfe der geeigneten Klassen der einen title, der jeweils dem Namen des Buches entspricht. Zudem hat ein Buch einen title Java API. Alle Bücher haben wird intern als eine Zeichenkette gespeichert. creator. Dieser kann z.B. MaxMustermann, Mustermann-Max, N_N, Springer oder sonstiges sein, was also einer beliebigen Zeichenkette bestehend aus Ziern, Zahlen, Binde- und/oder Unterstrichen entspricht. Auÿerdem wird die Zahl year ∈ [0, 2015] - das Erscheinungsjahr - auch intern als eine Zeichenkette bei allen Bücher gespeichert. Alle Bücher haben dann jeweils ein nur einen Titel, einen Urheber und Jahr-Attribut. Für jedes Buch-Objekt muss mindestens eines der genannten Attribute gesetzt sein. Alle nicht gesetzten Attribute haben den Wert unknown. C.3 Einfache Suchanfrage Implementieren Sie eine Suchfunktion, die dem Benutzer Ihres Programms eine erweiterte Suche nach Büchern erlaubt. Damit Ihr Programm exibel nach einem Buch suchen kann, soll die Suchfunktion die Eingabe nicht auf Gleichheit mit den Attribut-Werten der gespeicherten Bücher vergleichen (mittels tierdistanz nach Levenshtein edu/wiki/Vorlesung_Programmieren_WS14/ zwischen zwei Zeichenketten w1 und w2 berechnet. Im Folgenden sei ein wobei k(t) wir k(t) keyword einfacher Suchbegri dem Attributnamen und eine Funktion, die vk(t) (b) equals), sondern die Edihttps://sdqweb.ipd.kit. die Levenshtein-Distanz β(w1 , w2 ) 4 benutzen. Sie nden unter Übungsblätter auf keyword value eine Klasse, die Ihnen ein Suchbegri, formal t, der aus keyword = value besteht, dem korrespondierenden Attributwert entspricht. Auÿerdem sei für einen beliebigen einfachen Suchbegri als eine Funktion, die bei für ein Buch-Objekt b t ausgibt. Des weiteren denieren den Wert des Attributs mit dem Attributnamen k(t) in b vorhanden ist und für alle anderen Fälle eine leere Zeichenkette t ::= creator = reussner, dann liefert die Funktion k(t) creator zurück. Funktion vk(t) (t) reussner zurück. ausgibt, falls der Attributname zurückliefert. Ein Beispiel: Entsprechend liefert die Sei Implementieren Sie auf dieser Basis die Methode getNormalizedLevenshteinDistance(), die die norα(w1 , w2 ) für zwei Wörter malisierte Levenshtein-Distanz zurückliefert. Die normalisierte Levenshtein-Distanz 4 Zusatzinformationen zur genauen Berechnung der Levenshtein-Distanz speziell für Interessierte entnehmen Sie Anhang C.6.4 Seite 4 von 10 Programmieren Wintersemester 2014/15 w1 und w2 20.01.2015 18:00 liefert im Gegensatz zur Levenshtein-Distanz β(w1 , w2 ) immer Werte zwischen 0 und 1, indem die reguläre Levenshtein-Distanz durch die Länge des längeren der beiden Wörter geteilt wird. Unter Zuhilfenahme der soeben eingeführten Denitionen, sieht die normalisierte Levenshtein-Distanz in dieser Aufgabe wie folgt aus: α(vk(t) (t), vk(t) (b)) = β(vk(t) (t),vk(t) (b)) max(length(vk(t) (t)),length(vk(t) (b))) 1, , falls k(t) genau einem Attributnamen in b entspricht sonst (1) nicht unbedingt genau übereinstimmen, sondern sie können fast übereinstimmen. Dadurch können Sie eine gewisse Toleranz bei der Übereinstimmung der Attributwerte berücksichtigen. Bei der Suche wird angegeben, nach welchem Attribut eines Buches genau gesucht wird und welchen Attributwert dieses Attribut ungefähr haben soll. Dies bedeutet, die beschriebene Suchmethode Mit anderen Worten müssen zwei Attributwerte auch soll für eine einfache Suchanfrage t als Zeichenkette mit einem gesuchten Attribut und dem korrespondierenden Attributwert für ein bestimmtes Buch • true b α(vk(t) (t), vk(t) (b)) zwischen dem gesuchvk(t) (t) und dem korrespondierenden Attributwert vk(t) (b)) des Buches kleiner als (und nicht gleich) δ ∈ [0, 1] ist. δ wird dem Programm als Kommandozeilenparameter übergeben. Während zwischen den Attributwerten eine durch δ festgelegte Abweichung vorhanden sein darf, müssen die Attrizurückgeben, wenn die normalisierte Levenshtein-Distanz ten Attributwert butnamen hingegen genau übereinstimmen. • false C.4 Ein in allen anderen Fällen zurückgeben. Zusammengesetzte Suchanfragen zusammengesetzter Suchbegri ist ein Suchbegri, der aus zwei oder mehreren einfachen Suchbegrien besteht. Zunächst ist undeniert, wie mehrere einfache Suchbegrie miteinander verknüpft werden: liefert die Suche nach title=programmieren creator=reussner nur solche Bücher, in denen sowohl auch oder creator=reussner creator=reussner knüpfungsart wird als title=programmieren als title=programmieren, vorkommt? Oder werden alle Bücher zurückgeliefert, die entweder enthalten, aber nicht notwendigerweise beide Suchbegrie zusammen? Die erste Ver- Und-Verknüpfung (Konjunktion) bezeichnet. Die zweite Verknüpfungsart wird als Oder- Verknüpfung (Disjunktion) bezeichnet. Für die Komposition denieren wir die rekursive Funktion wiederum aus zwei weiteren Suchbegrien t1 und t2 ρ(t, b) für einen beliebigen Suchbegri bestehen kann, und ein beliebiges Buch-Objekt α(vk(t) (t), vk(t) (b)), ρ(t, b) = max(ρ(t1 , b), ρ(t2 , b)), min(ρ(t1 , b), ρ(t2 , b)), t falls t falls t falls b t, welcher wie folgt: ein einfacher Suchbegri ist = AND(t1 , = OR(t1 , t2 ) (2) t2 ) Hier wird für die Realisierung der Konjunktion die Maximumsfuntion und für die Realisierung der Disjunktion die Minimumsfunktion verwendet. Ein Beispiel: Liefert die normalisierte Levenshtein-Distanz title=programmieren und 0,3 für creator=reussner bei einem gespeicherten Buch, so liefert AND(title=programmieren, creator=reussner) eine normalisierte Levenshtein-Distanz von 0,3 und OR(title=programmieren, creator=reussner) eine normalisierte Levenshtein-Distanz von 0,2 für dasselbe Buch. jeweils 0,2 für Erweitern Sie die in Abschnitt C.3 beschriebene Methode so, dass sie auch zusammengesetzte Suchbegrie unterstützt. Dies bedeutet, dass die Methode nun für ein Buch-Objekt b • true zurückgibt, wenn die normalisierte Levenshtein-Distanz ρ(t, b) zwischen der gesamten Suchanfrage t und den korrespondierenden Attributwerten des Buches kleiner als (und nicht gleich) δ ∈ [0, 1] ist. δ wird Seite 5 von 10 Programmieren Wintersemester 2014/15 20.01.2015 18:00 dem Programm als Kommandozeilenparameter übergeben. Auch hier gilt: während zwischen den Attributwerten eine durch δ festgelegte Abweichung vorhanden sein darf, müssen die Attributnamen hingegen genau übereinstimmen. • false C.5 in allen anderen Fällen zurückgeben. Benutzereingaben: interaktiv Ihr Programm nimmt über die Konsole mittels Terminal.readLine() nur einen Befehl zwei Arten von Befehlen ::::::::::::::::::::::: entgegen. Wird dem Programm eine ungültige Benutzereingabe übergeben, wird eine Fehlermeldung beginnend mit Error, ausgegeben. C.5.1 Der search-Befehl t , Gesucht wird mit einer Suchanfrage der Form search t wobei entweder für einen einfachen Suchbegri oder für einen zusammengesetzten Suchbegri steht. Zusammengsetzte Suchbegrie werden wie folgt zusammengesetzt 5: t ::= nal | AND(t, t ) | OR(t, t ) nal ::= keyword =value keyword ::= title | year | creator value ::= (a-zA-Z0-9_-)+ Somit bestehen einfache Suchbegrie aus Ziern, Zahlen, Binde- und/oder Unterstrichen. Zusammengesetzte Suchbegrie können aber auch mittels der binären Operatoren AND und OR zusammengesetzt werden. Leerzeichen sollen entfernt werden, auÿerdem sollen alle Vergleiche unter Nichtbeachtung der Groÿ- und Kleinschreibung erfolgen. Alle einfachen Suchbegrie beinhalten ein Schlüsselwort, Attributnamens. Das Schlüsselwort kann somit entweder keyword in der obigen Grammatik, zur Angabe des title, year oder creator sein. Ein Gleichheitszei- chen = trennt jeweils das Schlüsselwort vom zu suchenden Attributwert, im Folgenden auch Wert genannt entspricht value in der obigen Grammatik. Die gespeicherten Attribute mit dem Wert unknown werden bei der Suche als nicht gesetzt betrachtet. Achten sie darauf, dass Sie die normalisierte Levenshtein-Distanz lediglich für den Vergleich der Attributwerte verwenden dürfen. Dies bedeutet, dass das Schlüsselwort genau mit einer der drei vorgegebenen Namen übereinstimmen muss. Andernfalls handelt es sich dabei um eine ungültige Suchanfrage. Ein Beispiel für eine ungültige Suchanfrage ist titel=programmieren search isbn=12345, also die Suche nach einer ISBN. Auch search bildet eine ungültige Suchanfrage. Beispiele für gültige Suchanfragen: • title=Java (einfaches Suchwort) • OR(title=Java, year=2006) (einfach zusammengesetzter Term) • AND(year=2006, title=Java_ist-auchEine_Insel) (einfach zusammengesetzter Term) • AND(year=2007, OR(title=JavaIstAuch_Insel, creator=Ullenboom)) (zweifach zusam- mengesetzter Term) C.5.2 Der quit-Befehl Dieser Befehl beendet das Programm. Es ndet keine Konsolenausgabe statt. ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 5 Für weitere Informationen siehe den jeweiligen Artikel zu Backus-Naur-Form und Regulärer Ausdruck in Wikipedia Seite 6 von 10 Programmieren Wintersemester 2014/15 20.01.2015 18:00 Ausgabe des Programms bei einer Suche Das Programm beantwortet eine Suchanfrage, indem jede Zeile der Eingabedatei in einer Zeile auf die Konsole ausgegeben wird, jeweils gefolgt von einem Komma und true oder false, abhängig davon, ob das jewei- lige Buch einen Treer bezüglich der Suchanfrage darstellt. Die Reihenfolge der Bücher innerhalb der Ausgabe entspricht exakt der Reihenfolge innerhalb der eingelesenen Datei (vergleiche C.6.3). Die Reihenfolge der Attributnamen-Attributwert-Paare eines Buches ist alphabetisch aufsteigend: creator, title, year. Attributnamen-Attributwert-Paare sind durch Kommas voneinander separiert. Attributname und Attributwert in einem Attributnamen-Attributwert-Paar sind mittels einem Gleichheitszeichen getrennt. Leerzeichen in der Ausgabe sind zu vermeiden. Alle Zeichen der Ausgabe sind klein geschrieben. Vermeiden Sie strikt weitere Ausgaben. Bei einer ungültigen Suchanfrage erfolgt eine aussagekräftige Fehlermeldung beginnend mit Error, . Beispiele für eine gültige Ausgabe: creator=galileocomputing,title=java_ist_auch_eine_insel,year=unknown,true creator=unknown,title=grundkursprogrammieren_in_java,year=2007,false creator=ralf_reussner,title=unknown,year=2006,true C.6 Benutzereingaben: Kommandozeilenparameter C.6.1 Bestimmung der Toleranzgrenze bei den Vergleichen Als erstes Kommandozeilenargument nimmt Ihr Programm eine Flieÿkommazahl δ ∈ [0, 1] in englischer Schreib- weise (also mit einem Punkt) entgegen, welches die Toleranzgrenze bei einem Vergleich mit der gesamten Suchanfrage vorgibt. Bei einer ungültigen Toleranzgrenze erfolgt eine aussagekräftige Fehlermeldung beginnend mit Error, . C.6.2 Bestimmung der Bücher in der Datenbank Als zweites Kommandozeilenargument nimmt Ihr Programm einen Pfad auf eine Textdatei entgegen. Diese Textdatei beinhaltet die in der Datenstruktur zu speichernden Bücher, sowie ihre Attribute. Ihr Programm baut intern eine Datenstruktur mit Hilfe der Klassen der Java API für alle vorkommenden Bücher, sowie ihre Attribute auf. Auch hier müssen Sie bei allen ungültigen Eingaben eine aussagekräftige Fehlermeldung beginnend mit Error, ausgeben. C.6.3 Aufbau des Eingabetextes Die Eingabedatei enthält eine oder mehrere Zeilen. Jede Zeile beinhaltet ein Buch, sowie dessen Attribute. Somit besteht jede Zeile aus einer Teilmenge der folgenden Schlüsselwörter {title, year, creator}. Achten Sie darauf, dass die Schlüsselwörter jeweils maximal einmal in einer Zeile vorkommen dürfen. Ein Gleichheitszeichen trennt dann die Schlüsselwörter von den jeweiligen Werten. Die Werte können auch hier wiederum nur aus Ziern, Zahlen, Binde- und/oder Unterstrichen bestehen. Sind die Attribute nur unvollständig vorhanden, werden bei unvorhandenen Attributen unknown als Wert gespeichert. Alle Schlüsselwort-Attributwert-Paare sind nur mittels einem Komma separiert. Ignorieren Sie Groÿ- und Kleinschreibung beim Speichern der Attribute und deren Werte in Ihrer Datenstruktur. Leere Textdateien sind nicht erlaubt. Geben Sie bei einem ungültigen oder nicht wohlgeformten Eingabetext eine aussagekräftige Fehlermeldung beginnend mit Error, aus. Duplikate Sie können davon ausgehen, dass keine Duplikate im Eingabetext vorkommen. C.6.4 Beispiel eines Eingabetextes Folgendes Beispiel präsentiert eine wohlgeformte Programmeingabe mit drei Zeilen: Seite 7 von 10 Programmieren Wintersemester 2014/15 20.01.2015 18:00 title=Java_ist_auch_eine_Insel,creator=GalileoComputing tITle=Grundkurs_Programmieren_iN_JAVA,year=2007 Creator=Ralf_Reussner,year=2006 Anhang: Levenshtein-Distanz Das Verstehen der genauen Berechnung der Levenshtein-Distanz ist für das Lösen der Aufgabe C nicht notwendig. Die Levenshtein-Distanz ist benannt nach ihrem Ernder dem russischen Mathematiker Wladimir Iossifowitsch Lewenstein, Man benutzt sie als Maÿ, das angibt, wie sehr sich zwei Zeichenketten unterscheiden. Die Levenshtein-Distanz wird oft auch als Editierdistanz bezeichnet, weil sie die minimale Anzahl von elementaren Zeichenoperationen (Einfügen, Löschen, Ersetzen) angibt, die nötig sind um ein Wort in ein anderes zu überführen. Einsatzgebiete sind beispielsweise automatische Korrekturvorschläge in Textverarbeitungssystemen oder aber auch die automatische Duplikat-Erkennung. Wir beginnen mit ein paar wenigen Denitionen, von denen die meisten intuitiv verständlich sind. Diese Denitionen benutzen wir, um die Funktionsweise des Levenshtein-Algorithmus genau zu beschreiben. Im Folgenden soll die Schreibweise mit w mit |w| π(w, 0) = . Wortes sei w[i] das i-te Zeichen im Wort w bezeichnen. Dabei legen wir fest, dass w[0] = , wobei im Allgemeinen das leere Wort (nichts) gemeint ist. Des weiteren denieren wir, dass die Länge eines bezeichnet werden soll. Ein Präx der Länge Ein Beispiel: Nehmen wir für w und w bezeichnen wir mit π(w, n). Auch hier w[0] = , w[1] = I, w[2] = n, w[3] = f, . . . |w| = 10. Dann noch zwei Beispiele für Präxe: π(w, 5) = Infor. w1 Um die Distanz zweier Wörter M |w2 |+1×|w1 |+1 , von die Zeichenkette Informatik. Dann ist und so weiter. Des weiteren ist die Länge der Zeichenkette π(w, 3) = Inf n die und w2 zu berechnen, erzeugt der Levenshtein-Algorithmus eine Matrix an jeder Stelle m(i, j) die Editierdistanz der Präxe π(w2 , i) und π(w1 , j) enthält. Dabei kann die Editierdistanz für zwei Präxe an jeder Stelle aus den Editierdistanzen der jeweils kürzeren Präxe berechnet werden (Beachten Sie, dass im Falle von Matrizen der Zeilenindex immer vor dem Spaltenindex genannt wird). Beim Levenshtein-Algorithmus ergibt sich die Editierdistanz zweier Wörter aus den Editierdistanzen ihrer Präxe. Begonnen wird mit der Editierdistanz der leeren Präxe d ä m l i c h π(w2 , 0) n ä h m l i c h 0 1 2 3 4 5 6 7 8 1 1 2 3 4 5 6 7 8 2 2 1 2 3 4 5 6 7 3 3 2 2 2 3 4 5 6 4 4 3 3 3 2 3 4 5 5 5 4 4 4 3 2 3 4 6 6 5 5 5 4 3 2 3 7 7 6 5 6 5 4 3 2 und π(w1 , 0) also . delete insert Abbildung 1: Beispiel für w1 = nähmlich und w2 = dämlich Um die minimale Anzahl an Elementaroperationen zu berechnen die nötig ist um w1 in w2 zu überführen, denieren wir zunächst für jede der drei Elementaroperationen Einfügen, Löschen und Ersetzen eine Kostenfunktionen. Für (i, j) ∈ {0, 1, . . . , |w2 |} × {0, 1, . . . , |w1 |} seien insert, delete Seite 8 von 10 und replace wie folgt deniert: Programmieren Wintersemester 2014/15 ( delete(i, j) = 20.01.2015 18:00 ∞, m(i, j − 1) + 1, falls j<1 sonst ( ∞, falls i < 1 m(i − 1, j) + 1, sonst falls i < 1 ∞, replace(i, j) = m(i − 1, j − 1), falls i ≥ 1 m(i − 1, j − 1) + 1, sonst insert(i, j) = Nach einem Initialisierungsschritt in dem oder und j<1 j ≥ 1 und w1 [j] = w2 [i] m(0, 0) = 0 gesetzt wird, werden alle weiteren Einträge zeilenweise aus m(i, j) und i, j ≥ 1 jeweils das Minimum der Kostenfunktionen den vorherigen Einträgen berechnet, indem für gewählt wird: m(i, j) = min delete(i, j), insert(i, j), replace(i, j) Beachten Sie, dass oben zugunsten einer schlanken Denition welches mit Integer.MAX_VALUE ∞ im Wertebereich der Funktionen vorkommt, realisiert wurde. In Abbildung 1 sehen Sie eine voll ausgefüllte Levenshtein-Matrix für die beiden Zeichenketten nähmlich und dämlich. Die Levenshtein-Distanz ist in diesem Fall 2. Seite 9 von 10 Programmieren Wintersemester 2014/15 20.01.2015 18:00 Das Eulenfest am 20. Januar Seite 10 von 10