Programmieren–Wintersemester 2014/15 - Übungsblatt 6

Werbung
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
Herunterladen