Textalgorithmen

Werbung
Vorbemerkungen
Übungen
Textalgorithmen
Peter Becker
FH Bonn-Rhein-Sieg
Fachbereich Angewandte Informatik
[email protected]
• In die Vorlesung integriert
• Bearbeitungszeit: abhängig von den Aufgaben, i.d.R. eine oder zwei
Wochen
Vorlesung Sommersemester 2002
• Theorie- und Programmieraufgaben
• Programmieraufgaben können in einer beliebigen Programmiersprache gelöst werden, wenn nicht explizit eine Sprache (Java, C) vorgeben wird.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Vorbemerkungen
Allgemeines zur Vorlesung
2
Vorbemerkungen
TB, LN, Prüfung
• Es gibt eine Homepage zur Vorlesung:
http://www2.inf.fh-rhein-sieg.de/˜pbecke2m/textalgorithmen/
• Die Vorlesung wird folienbasiert gehalten.
• TB: Anwesenheit, ein paar Übungsaufgaben demonstrieren
• Die Folien zur Vorlesung (Skript) stehen auf der Homepage vor der
Vorlesung zur Verfügung.
• LN: Übungsaufgaben ++, (Richtlinie 50% der zu vergebenden Punkte)
• Format: PDF, zwei- und vierseitig
• Sie können also die ausgedruckten Folien mit in die Vorlesung bringen und dort mit schriftlichen Bemerkungen versehen.
• Benutzen Sie zum Drucken bitte die vierseitige Version des Skriptes.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3
Vorbemerkungen
1. Suche von Mustern
Einf ¨uhrung
Literatur
1 Suche von Mustern
M. Crochemore, W. Rytter, Text Algorithms, Oxford University Press,
1994.
Die Suche von einem Muster in einem Text wird auch als String Matching oder Pattern Matching bezeichnet.
D. Gusfield, Algorithms on Strings, Trees, and Sequences, Cambride
University Press, 1997.
Generell besteht die Aufgabe darin,
• einen String (das Muster, Pattern) der Länge m
L. Schmitz, Syntaxbasierte Programmierwerkzeuge, Teubner, 1995.
• in einem Text der Länge n zu finden,
wobei n > m gilt.
Je nach Freiheitsgraden bei der Suche unterscheidet man verschiedene
Arten von String-Matching-Problemen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4
Vorbemerkungen
Inhalt
1. Suche von Mustern
6
Einf ¨uhrung
Arten von String-Matching-Problemen
1. Suche von Mustern
Exaktes String-Matching: Wo tritt ein String pat in einem Text text
auf? Beispiel: fgrep
2. Suffix-Bäume
Matching von Wortmengen: Gegeben sei eine Menge S von Strings.
Wo tritt in einem Text ein String aus S auf? Beispiel: agrep
3. reguläre Ausdrücke, approximative Mustersuche
4. lexikalische Analyse und Parsing
Matching regulärer Ausdr ücke: Welche Stellen in einem Text passen
auf einen regulären Ausdruck? Beispiel: grep, egrep
5. XML und Analyse von XML-Dokumenten
Approximatives String-Matching: Welche Stellen in einem Text passen am besten auf ein Muster (Best-Match-Anfrage)?
6. Textkompression
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
7
1. Suche von Mustern
Einf ¨uhrung
Welche Stellen in einem Text stimmen mit einem Muster bis auf d
Fehler überein (Distance-Match-Anfrage)? Beispiel: agrep
Editierdistanz: Wie kann man am “günstigsten” einen String s in einen
String t überführen? Beispiel: diff
Wo braucht man String-Matching-Verfahren? Z.B.:
1. Suche von Mustern
Einf ¨uhrung
• s[i] bezeichnet das i-te Element eines Strings s (1 ≤ i ≤ |s|).
s[i . . . j] bezeichnet den String s[i]s[i + 1] . . . s[j]. Für i > j gelte
s[i . . . j] = .
• Für einen String s (mit m = |s|) bezeichnet sR die Umkehrung
s[m]s[m − 1] · · · s[1] von s.
• Für zwei String x und y gilt x = y genau dann, wenn |x| = |y| = m
und x[i] = y[i] für alle 1 ≤ i ≤ m gilt.
• Volltextdatenbanken, Retrievalsysteme, Suchmaschinen
• Bioinformatik
• Wenn ω = xyz ein String ist, dann ist x ein Präfix und z ein Suffix
von ω.
☞ In diesem Kapitel lernen wir effziente Algorithmen für exaktes StringMatching kennen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
8
Einf ¨uhrung
Gilt ω 6= x (ω 6= z), dann ist x (z) ein echter Präfix (echter Suffix) von
ω.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
10
Einf ¨uhrung
Bezeichnungen
• Ein String x (mit m = |x|) heißt Substring (Faktor) von y, wenn ein i
existiert mit x = y[i . . . i + m − 1]. Andere Sprechweisen: x tritt in y
an Position i auf bzw. Position i ist ein Match für x in y.
• Ein Alphabet Σ ist eine endliche Menge von Symbolen. |Σ| bezeichnet die Kardinalität von Σ.
• x (mit m = |x|) heißt Subsequenz von y wenn Positionen i1 < i2 · · · <
im existieren mit x = y[i1]y[i2] . . . y[im].
• Ein String (Zeichenkette, Wort) s über einem Alphabet Σ ist eine endliche Folge von Symbolen aus Σ. |s| bezeichnet die Länge von s.
• bezeichnet den leeren String.
• Wenn x und y Strings sind, dann bezeichnet xy die Konkatenation
von x und y.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
9
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
11
1. Suche von Mustern
Einf ¨uhrung
1. Suche von Mustern
Der naive Algorithmus
• Zunächst wird die Variante “von links nach rechts” betrachtet.
Exaktes String-Matching
Problem 1.1. [Exaktes String-Matching] Gegeben sind die Strings
pat und text.
(a) Man bestimme, ob pat ein Substring von text ist.
(b) Man bestimme die Menge aller Positionen, an denen pat in text auftritt. Diese Menge wird mit M AT CH(pat, text) bezeichnet.
• Im folgenden wird nur die Variante (a) von Problem 1.1 betrachtet.
• Algorithmen für die Variante (b) erhält man durch einfache Modifikationen der Algorithmen für (a).
Algorithmus 1.1. [Naives String-Matching von links nach rechts]
i := 1
while i ≤ n − m + 1 do
j := 1
while j ≤ m and pat[j] = text[i + j − 1] do j := j + 1 end
if j = m + 1 then return true
i := i + 1
end
return false
Satz 1.1. Der naive Algorithmus 1.1 löst Problem 1.1 in Zeit O(nm)
und Platz O(m).
• Im folgenden sei m = |pat| und n = |text|.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
12
Der naive Algorithmus
Der naive Algorithmus
1. Suche von Mustern
14
Der naive Algorithmus
Analyse für naives String-Matching
Der naive Ansatz besteht darin, für jede Position von text (bzw. solange
pat ab der aktuellen Position in text paßt) von neuem zu testen, ob pat
an dieser Position auftritt.
• Für pat = am−1b und text = an benötigt Algorithmus 1.1
(n − m + 1)m = nm − m2 + m
Das allgemeine Schema für solch einen naiven Algorithmus lautet:
for i := 1 to n − m + 1 do
man prüfe, ob pat = text[i . . . i + m − 1] gilt
Zeichenvergleiche (Worst Case).
• Die Prüfung kann nun “von links nach rechts” oder “von rechts nach
links” erfolgen.
• Dies führt zu unterschiedlichen naiven Algorithmen und darauf aufbauend zu unterschiedlichen Ansätzen der Verbesserung.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
13
• Bei einem binären Alphabet und zufällig erzeugten pat und text (jedes Zeichen unabhängig und jedes Symbol mit Wahrscheinlichkeit
1/2) ergibt sich für die durchschnittliche Anzahl an Zeichenvergleichen:
(2 − 2−m)n + O(1)
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
15
1. Suche von Mustern
Der naive Algorithmus
• Trotz der im Durchschnitt linearen Laufzeit lohnt sich der Einsatz von
“besseren” String-Matching-Algorithmen, denn:
1. Suche von Mustern
Morris und Pratt
Veranschaulichung:
pat:
– die nachfolgenden String-Matching-Algorithmen haben sich nicht
nur in der Theorie, sondern auch in der Praxis als erheblich effizienter erwiesen, und
– die Realität gehorcht nicht immer den Gesetzen der Wahrscheinlichkeitstheorie.
a b c a - - - - -
pat:
a b c a b c d - - - - -
text: - - - - - a b c a b c a - - - - ↑
↑
↑
i
i+s i+j−1
s ist hier der Betrag, um den pat nach rechts verschoben wird.
Nach einem Mismatch an Position j von pat kann nur dann an i + s ein
Match vorliegen, wenn pat[1 . . . j − s − 1] ein Suffix von pat[1 . . . j − 1]
ist.
Mit k := j − s folgt: pat[1 . . . k − 1] ist Suffix von pat[1 . . . j − 1].
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
16
Morris und Pratt
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
18
1. Suche von Mustern
Morris und Pratt
Veranschaulichung:
String-Matching nach Morris und Pratt
naechstmoeglicher Match
s
Algorithmus 1.1 ist naiv im folgenden Sinn: nach jedem Mismatch an
Stelle j von pat wird vergessen, daß pat bis zur Position j − 1 auf text
paßt.
Mismatch
Pattern
1
Kommt es an Stelle j von pat zu einem Mismatch, so gilt:
pat[1 . . . j − 1] = text[i . . . i + j − 2]
j
Text
Dies kann wie folgt ausgenutzt werden: Angenommen, pat tritt in text
an einer Position i + s mit i < i + s < i + j − 1 auf. Dann muß gelten:
pat[1 . . . j − s − 1] = pat[1 + s . . . j − 1]
Damit man keinen Match verpaßt, muß s möglichst klein und somit k
möglichst groß gewählt werden.
Konsequenzen für einen verbesserten Algorithmus:
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
17
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
19
1. Suche von Mustern
Morris und Pratt
• Man ermittle in einer Preprocessingphase zu jedem 1 ≤ j ≤ m das
größte k, so daß pat[1 . . . k − 1] echter Suffix von pat[1 . . . j − 1] ist.
Der entsprechende Betrag wird mit border[j] bezeichnet.
1. Suche von Mustern
Morris und Pratt
Lemma 1.2. Wenn border[j] (für 1 ≤ j ≤ m) bereits vorliegt, löst Algorithmus 1.2 Problem 1.1 in Zeit O(n).
Beweis.
border[j] :=
max {k | pat[1 . . . k − 1] = pat[j − k + 1 . . . j − 1]}
• Es gibt höchstens n − m + 1 nicht erfolgreiche Vergleiche (nämlich
höchstens einer für jedes i).
1≤k≤j−1
bzw.
• Man betrachte nun den Term i + j. Es gilt 2 ≤ i + j ≤ n + 1.
border[j] :=
max {k | pat[1 . . . k−1] ist echter Suffix von pat[1 . . . j−1]}
1≤k≤j−1
• Immer wenn der Vergleich pat[j] = text[i + j − 1] erfolgreich war, wird
i + j um eins erhöht.
Weiterhin gelte border[1] = 0
• Insgesamt wird i + j in (A) und (B) nicht verringert.
• Im Algorithmus schiebe man bei einem Mismatch an Position j des
Pattern dieses um s = j − border[j] Stellen nach rechts.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
20
1. Suche von Mustern
Morris und Pratt
• Durch die Maximalität ist s ein “safe shift”.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
22
Morris und Pratt
⇒ und somit O(n) Vergleiche insgesamt.
Algorithmus 1.2. [Morris und Pratt]
i := 1; j := 1
while i ≤ n − m + 1 do
while j ≤ m and pat[j] = text[i + j − 1] do
j := j + 1
end
if j = m + 1 then return true
i := i + j − border[j]
j := max(border[j], 1)
end
return false
⇒ Es gibt ≤ n erfolgreiche Vergleiche
2
Es bleibt das Problem, border[j] berechnen zu müssen. Zunächst ein
Beispiel für border[j].
(A)
(B)
21
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
23
1. Suche von Mustern
Morris und Pratt
1. Suche von Mustern
Fibonacci-Strings
Morris und Pratt
Berechnung von border[j]
Definition 1.1. Der n-te Fibonacci-String Fn (n ≥ 0) ist wie folgt definiert:
• F0 = • Zur Berechnung der Tabelle border wird eine spezielle Version von
Algorithmus 1.2 benutzt.
• Man nutzt dabei die aus dem Beweis von Lemma 1.2 bekannte Tatsache aus, daß der Betrag i + j nie verringert wird.
• F1 = b
• F2 = a
• Fn = Fn−1Fn−2 für n > 2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
24
1. Suche von Mustern
Morris und Pratt
1
a
0
2
b
1
3
a
1
4
a
2
5
b
2
6
a
3
7
b
4
8
a
3
9
a
4
10
b
5
11
a
6
12
a
7
13
b
5
1
a
0
2
b
1
3
a
1
4
b
2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5
c
3
6
a
1
Morris und Pratt
7
a
2
8
b
2
9
a
3
10
c
4
11
c
1
12
b
1
13
a
1
border[1] := 0
for j := 2 to m do border[j] := 1 end
i := 2
j := 1
while i ≤ m do
while i + j − 1 ≤ m and pat[j] = pat[i + j − 1] do
j := j + 1
border[i + j − 1] := j
end
i := i + j − border[j]
j := max(border[j], 1)
end
Für ababcaabaccba ergibt sich:
j
pat[j]
border[j]
1. Suche von Mustern
26
Algorithmus 1.3.
Beispiel 1.1. border[j] lautet für F7:
j
pat[j]
border[j]
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
25
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
27
1. Suche von Mustern
Morris und Pratt
Lemma 1.3. Algorithmus 1.3 benötigt zur Berechnung der Tabelle
border höchstens O(m) Vergleiche.
Beweis. Analog zu Lemma 1.2. 2
1. Suche von Mustern
Knuth, Morris und Pratt
Es kommt also an der gleichen Stelle des Textes direkt wieder zu einem
Mismatch.
Dies war abzusehen, denn für pat gilt: pat[6] = pat[border[6]]
Veranschaulichung:
zwangslaeufiger Mismatch
s
Mismatch
!= notwendig
Pattern
1
j
Text
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
28
1. Suche von Mustern
Knuth, Morris und Pratt
Der Algorithmus von Morris und Pratt kann noch effizienter gemacht
werden. Man betrachte folgendes Beispiel:
a b a a b a - -
1. Suche von Mustern
Knuth, Morris und Pratt
pat[k] 6= pat[j]
verschärft werden.
Konsequenzen für eine Verbesserung: man benutze statt border[j] die
folgende Variante sborder[j]:
text: - - - - - a b a a b c - Es kommt für j = 6 zu einem Mismatch. Wegen border[6] = 3 wird pat
um drei Zeichen nach rechts geschoben.
pat:
30
Offensichtlich kann die bisher genutzte Bedingung, daß pat[1 . . . k − 1]
Suffix von pat[1 . . . j − 1] ist, um die Bedingung
Knuth, Morris und Pratt
pat:
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
sborder[j] :=
max {k | pat[1 . . . k−1] = pat[j−k+1 . . . j−1] und pat[k] 6= pat[j]}
1≤k≤j−1
Falls kein solches k existiert, gelte sborder[j] = 0
a b a a b a - -
text: - - - - - a b a a b c - Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
29
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
31
1. Suche von Mustern
Knuth, Morris und Pratt
1
a
0
0
2
b
1
1
3
a
0
1
4
a
2
2
5
b
1
2
6
a
0
3
7
b
4
4
8
a
0
3
9
a
2
4
10
b
1
5
11
a
0
6
12
a
7
7
Knuth, Morris und Pratt
Satz 1.4. Die Algorithmen 1.3 und 1.4 lösen Problem 1.1 in Zeit O(n +
m) und Platz O(m).
Beispiel 1.2. sborder[j] lautet für F7 (vgl. Beispiel 1.1):
j
pat[j]
sborder[j]
border[j]
1. Suche von Mustern
13
b
1
5
Beweis. sborder kann wie border in Zeit O(m) berechnet werden. Durch
die Verwendung von sborder statt border finden in Algorithmus 1.4 nicht
mehr Vergleiche statt als in Algorithmus 1.2. 2
Algorithmus 1.4. [Knuth, Morris und Pratt] Der Algorithmus von Knuth,
Morris und Pratt ist identisch zu Algorithmus 1.2 bis auf die Tatsache,
daß statt border die strengere Variante sborder verwendet wird.
Zur Berechnung von sborder sind ebenfalls nur marginale Änderungen
gegenüber Algorithmus 1.3 notwendig.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
32
Knuth, Morris und Pratt
Algorithmus 1.5. [Berechnung von sborder]
1. Suche von Mustern
34
Knuth, Morris und Pratt
Beispiel 1.3. [Algorithmus von Knuth, Morris und Pratt] Der String
F7 wird in dem String
for j := 1 to m do sborder[j] := 0 end
i := 2
j := 1
while i ≤ m do
while i + j − 1 ≤ m and pat[j] = pat[i + j − 1] do
j := j + 1
sborder[i + j − 1] := sborder[j]
end
sborder[i + j − 1] := max(j, sborder[i + j − 1])
i := i + j − sborder[j]
j := max(sborder[j], 1)
end
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
abaababaabacabaababaabaab
gesucht. Nach dem Start des Algorithmus ergibt sich ein Mismatch für
j = 12 und i = 1.
j
↓
a b a a b a b a a b a a b
a b a a b a b a a b a c a b a a b a b a a b a a b
↑
i
33
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
35
1. Suche von Mustern
Knuth, Morris und Pratt
Nun erhält man i := 1 + 12 − sborder[12] = 6 und j := sborder[12] = 7.
j
↓
a b a a b a b a a b a a b
Der Algorithmus von Boyer und Moore
Algorithmus 1.6. [naives String-Matching von rechts nach links]
i := 1
while i ≤ n − m + 1 do
j := m
while j ≥ 1 and pat[j] = text[i + j − 1] do j := j − 1 end
if j = 0 then return true
i := i + 1
end
return false
Es tritt wieder ein Mismatch auf, deshalb j := 4 und i := 9.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
36
Knuth, Morris und Pratt
Die Mismatches setzen sich fort bis j = 1 und i = 13.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
38
Boyer und Moore
Der Algorithmus von Boyer und Moore basiert auf der folgenden Überlegung:
j
↓
a b a a b a b a a b a a b
• Tritt in Algorithmus 1.6 an Stelle j ein Mismatch auf und kommt
pat[j + 1 . . . m] nicht ein weiteres mal in pat als Substring vor, so
kann pat gleich um m Zeichen nach rechts verschoben werden.
a b a a b a b a a b a c a b a a b a b a a b a a b
↑
i
• Vergleicht man dagegen von links nach rechts, kann pat nach einem
Mismatch an Position j nie um mehr als j Positionen nach rechts
verschoben werden (vgl. Algorithmus 1.2).
Ab hier wird nun ein Match ermittelt.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Boyer und Moore
Der Algorithmus von Boyer und Moore kann als eine verbesserte Variante eines naiven String-Matching-Algorithmus angesehen werden, bei
dem pat mit text von rechts nach links verglichen wird.
a b a a b a b a a b a c a b a a b a b a a b a a b
↑
i
1. Suche von Mustern
1. Suche von Mustern
37
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
39
1. Suche von Mustern
Boyer und Moore
Veranschaulichung:
1. Suche von Mustern
Boyer und Moore
Veranschaulichung:
naechstmoeglicher Match
Mismatch
pat:
Vergleich
pat:
- - - - a b c b c
↑
j
text: - - - - - - a b c a b c - - - - ↑
↑
i
i+j−1
Pattern
j
1
Text
j−s
↓
- - - - a b c b c
m
????
Damit man keinen Match verpaßt, muß s wiederum möglichst klein
gewählt werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
40
Boyer und Moore
Kommt es in Algorithmus 1.6 an der Stelle j von pat zu einem Mismatch,
so gilt
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
42
1. Suche von Mustern
Boyer und Moore
Veranschaulichung:
naechstmoeglicher Match
• pat[j + 1 . . . m] = text[i + j . . . i + m − 1] und
fuer BM2 !=
Vergleich
• pat[j] 6= text[i + j − 1].
= fuer BM1
Mismatch
Pattern
Dies kann wie folgt ausgenutzt werden: Angenommen, pat tritt in text an
einer Position i < i + s < i + m auf. Dann müssen die beiden folgenden
Bedingungen gelten:
j
1
Text
m
????
(BM1) für alle j < k ≤ m : k ≤ s oder pat[k − s] = pat[k]
(BM2) s < j =⇒ pat[j − s] 6= pat[j]
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
41
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
43
1. Suche von Mustern
Boyer und Moore
Die entsprechenden Werte werden in einer Preprocessingphase ermittelt und in der Shift-Tabelle D abgelegt.
D[j] := min{s| (BM1) und (BM2) gilt für j und s }
1. Suche von Mustern
Boyer und Moore
Algorithmus 1.7 kann noch weiter verbessert werden: Tritt an Stelle m
von pat (also bereits beim ersten Vergleich) ein Mismatch auf, so wird
pat nur um eine Stelle nach rechts verschoben.
Es sei
s>0
last[c] := max {j | pat[j] = c}
1≤j≤m
Der Algorithmus von Boyer und Moore verwendet nun im Falle eines
Mismatches an Position j den in D[j] abgelegten Wert, um pat nach
rechts zu verschieben.
und last[c] := 0 falls c nicht in pat auftritt.
last[c] gibt für ein c ∈ Σ die jeweils letzte Position von c in pat an. Kommt
es nun an Stelle j zu einem Mismatch, kann statt
i := i + D[j]
die Anweisung
i := i + max(D[j], j − last[text[i + j − 1]])
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
44
1. Suche von Mustern
Boyer und Moore
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
1. Suche von Mustern
46
Boyer und Moore
Algorithmus 1.7. [Algorithmus von Boyer und Moore]
verwendet werden. Damit ergeben sich noch größere Verschiebungen.
i := 1
while i ≤ n − m + 1 do
j := m
while j ≥ 1 and pat[j] = text[i + j − 1] do j := j − 1 end
if j = 0 then return true
i := i + D[j]
end
return false
Bemerkungen:
1
a
8
• Wird nur der Occurence-Shift verwendet, d.h. die Verschiebeanweisung lautet
i := i + max(1, j − last[text[i + j − 1]])
D[j] lautet für F7:
Beispiel 1.4.
j
pat[j]
D[j]
• Verschiebungen der Länge j −last[text[i+j −1]] heißen OccurrenceShift.
2
b
8
3
a
8
4
a
8
5
b
8
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6
a
8
7
b
8
8
a
3
9
a
11
10
b
11
11
a
6
12
a
13
13
b
1
so spricht man von einem vereinfachten Boyer-Moore-Algorithmus.
• Die Worst-Case-Laufzeit des vereinfachten Boyer-Moore-Algorithmus
beträgt O(nm).
45
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
47
1. Suche von Mustern
Boyer und Moore
1. Suche von Mustern
• Auf gewöhnlichen Texten verhält sich die vereinfachte Version i.d.R.
nur marginal schlechter als die ursprüngliche Version.
Die Situation ist ähnlich wie beim Verfahren von Morris und Pratt. Statt
eines Präfixes muß hier aber ein Suffix von pat mit einem inneren Teil
von pat übereinstimmen.
• Bei kleinem |Σ| ist die Occurence-Heuristik i.d.R. nutzlos.
Vorgehensweise für die erste Phase: man berechnet (für 0 ≤ j ≤ m)
rborder[j] mit
naechstmoeglicher Match fuer Occurence
rborder[j] :=
Mismatch
Vergleich
j
Text
max {k | pat[j + 1 . . . j + k − 1] = pat[m − k + 2 . . . m]}
1≤k≤m−j
bzw.
Pattern
1
Boyer und Moore
rborder[j] :=
m
max {k | pat[j+1 . . . j+k−1] ist echter Suffix von pat[j+1 . . . m]}
1≤k≤m−j
Weiterhin gelte rborder[m] = 0.
????
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
48
1. Suche von Mustern
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Boyer und Moore
50
1. Suche von Mustern
Es bleibt das Problem, die Shift-Tabelle D zu berechnen. Dies geschieht
in zwei Phasen. In der ersten Phase werden nur Verschiebungen der
Form D[j] < j betrachtet. Für solche Verschiebungen muß gelten:
Boyer und Moore
Beispiel 1.5. rborder[j] lautet für F7:
j
pat[j]
rborder[j]
(BM1) pat[j + 1 . . . m] = pat[j + 1 − s . . . m − s]
0
6
1
a
5
2
b
4
3
a
3
4
a
2
5
b
6
6
a
5
7
b
4
8
a
3
9
a
2
10
b
1
11
a
1
12
a
1
13
b
0
Man beachte:
(BM2) pat[j − s] 6= pat[j]
• rborder[j] entspricht border[j] für patR.
Veranschaulichung:
pat: *
pat: *
*
*
*
*
*
*
b
a
b
a
a
b
b
↑
j−s
a
b
a
↑
j
a
b
a
a
b ←
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
a
a
b
• Dementsprechend läßt sich rborder[j] analog zu Algorithmus 1.3 berechnen, wobei man nun aber von rechts nach links vorgeht.
→
s
49
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
51
1. Suche von Mustern
Boyer und Moore
1. Suche von Mustern
Boyer und Moore
Beispiel 1.6. D[j] nach der ersten Phase für den String F7:
i := m − 1
j := 1
while i >= 0 do
while i − j + 1 >= 1 and pat[m − j + 1] = pat[i − j + 1] do
j := j + 1
rborder[i − j + 1] = j
end
i := i − j + rborder[m − j + 1]
j := max(rborder[m − j + 1], 1)
end
j
pat[j]
D[j]
1
a
13
2
b
13
3
a
13
4
a
13
5
b
13
6
a
13
7
b
13
8
a
3
9
a
13
10
b
13
11
a
6
12
a
13
13
b
1
Wegen (BM2) treten relevante Situationen zur Berechnung von D[j] nur
im Falle eines Mismatch in der inneren While-Schleife auf. Dementsprechend wird zur Berechnung von D[j] der Algorithmus hinter der inneren
While-Schleife um die folgenden Anweisungen erweitert:
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
52
1. Suche von Mustern
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Boyer und Moore
1. Suche von Mustern
(BM1) pat[1 . . . t − 1] = pat[m − t + 2 . . . m] mit j ≤ m − t + 1
gelten. (BM2) ist in dieser Phase stets wahr und braucht nicht weiter
betrachtet zu werden.
Veranschaulichung:
pat: *
*
*
Boyer und Moore
In der zweiten Phase werden Verschiebungen mit D[j] ≥ j betrachtet.
Für solche Verschiebungen muß die Bedingung
if j > 1 then
s := m − i
t := i − j + 1
if t + s > s then
D[t + s] = min(s, D[t + s])
endif
endif
pat: *
54
Veranschaulichung:
*
*
*
*
b
a
b
↑
t=i−j+1
b
a
b
a
a
b
a
a
↑
t+s
b
↑
i
a
a
b ←
a
a
pat: a b a a b a b a a b a a b
→
s
pat: a b a a b a b a a b a a b ← s = m − t + 1 →
↑
↑
↑
j
t−1
m−t+2
Damit steht der Algorithmus für die erste Phase.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
b
53
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
55
1. Suche von Mustern
Boyer und Moore
1. Suche von Mustern
Boyer und Moore
Algorithmus 1.8. [Berechnung der Shift-Tabelle f ür Boyer und Moore]
naechstmoeglicher Match
Der größte mögliche Wert für t ergibt sich durch rborder[0] (Länge des
längsten Substrings, der sowohl echter Präfix als auch echter Suffix ist).
/* Initialisierung */
rborder[m] := 0; D[m] := 1
for j := m − 1 downto 0 do
rborder[j] = 1; D[j] = m
end
/* Phase 1 */
i := m − 1
j := 1
while i >= 0 do
while i − j + 1 >= 1 and pat[m − j + 1] = pat[i − j + 1] do
j := j + 1
rborder[i − j + 1] = j
end
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Vergleich
= fuer BM1
Mismatch
Pattern
1
Text
t
j
m
????
Es werden nun in absteigender Reihenfolge mögliche Werte für t betrachtet, und D[j] wird entsprechend korrigiert.
1. Suche von Mustern
56
Boyer und Moore
Die weiteren möglichen Werte für t ergeben sich durch rborder[m−t+1].
t := rborder[0]
l := 1
while t > 0 do
s=m−t+1
for j := l to s do
D[j] := min(D[j], s)
end
t := rborder[s]
l := s + 1
end
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
57
1. Suche von Mustern
58
Boyer und Moore
if j > 1 then
s := m − i
t := i − j + 1
if t + s > s then
D[t + s] = min(s, D[t + s])
endif
endif
i := i − j + rborder[m − j + 1]
j := max(rborder[m − j + 1], 1)
end
/* Phase 2 */
t := rborder[0]
l := 1
while t > 0 do
s=m−t+1
for j := l to s do
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
59
1. Suche von Mustern
Boyer und Moore
1. Suche von Mustern
Boyer und Moore
D[j] := min(D[j], s)
end
t := rborder[s]
l := s + 1
end
Bemerkungen:
Beispiel 1.7. [Algorithmus von Boyer und Moore] Der String F7 wird
in dem String abaababaabacabaababaabaab gesucht.
• Würde man statt (BM1) und (BM2) nur (BM1) verwenden, so wäre
keine lineare Laufzeit mehr gewährleistet (O(mn)).
a
a b
a b a a b a b a
a b a a b a b a a
a
b
a
a
b
• Als scharfe obere Schranke für die Anzahl an Zeichenvergleichen
ergibt sich 3n.
b
a
a
b
a
a
a
b
a
a
a
a
b
a
a
b
b
b
a
b
b
a
a
b
a
a
b
a
a
b
a
a
b
a
a
b
a
b
b
a
a
a a b a a b
a a b
a b
b
• Sucht man mit dem Algorithmus von Boyer und Moore nach allen
Matches für pat in text, so ist die Laufzeit ebenfalls O(mn).
a b a a b a b a a b a c a b a a b a b a a b a a b
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
60
1. Suche von Mustern
Boyer und Moore
Beispiel 1.8. [Shift-Tabellen f ür Boyer/Moore]
datenbank
999999991
kuckuck
3336661
retrieval
999999991
rokoko
662641
papa
2241
2. Suffix-B¨
aume
62
Trie
2 Suffix-Bäume
compiler
88888881
• In diesem Abschnitt sollen Datenstrukturen zur Beschleunigung des
exakten String-Matchings (Problem 1.1) untersucht werden.
abrakadabra
77777771131
00
• Konkret liegt folgende Situation vor:
Satz 1.5. Algorithmus 1.7 löst Problem 1.1(a) in Zeit O(n + m) und
Platz O(m).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
61
– Gegeben ist ein (evtl. sehr langer) String text.
– Man hat Anfragen an text gemäß Problem 1.1, d.h. es sind alle
(oder ein) Vorkommen eines beliebigen Strings pat in text aufzufinden.
– Gesucht ist eine Datenstruktur D, mit der nach einer Preprocessingphase für text solche Anfragen in sublinearer Zeit beantwortet
werden können.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
63
2. Suffix-B¨
aume
Trie
Anforderungen an die Datenstruktur D:
2. Suffix-B¨
aume
Trie
mit der Eigenschaft:
∀pat ∈ P ∃k : pat = path(k)
• Die Größe von D sollte linear in |text| sein.
• D sollte effizient (möglichst in O(|text|)) aufgebaut werden können.
a
b
• Problem 1.1 (exaktes String-Matching) sollte mit Hilfe von D in sublinearer Zeit gelöst werden können.
b
☞ Grundidee: Man finde eine geeignete Datenstruktur zur Repräsentation von Wortmengen.
Beispiel 2.1. [Trie] Für die Menge P = {ab, ba, babb, bb} von
Strings ergibt sich der Trie:
a
b
b
b
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
64
2. Suffix-B¨
aume
Trie
Trie
2. Suffix-B¨
aume
66
Trie
Stringsuche mit Hilfe eines Tries
Definition 2.1. Es sei Σ ein endliches Alphabet. Ein Trie (auch ΣBaum genannt) ist ein Wurzelbaum mit den folgenden Eigenschaften:
Es sei P eine Menge von Strings. Dann gilt:
• T rie(P ) kann in linearer Zeit bezüglich der Gesamtlänge der in P
enthaltenen Strings aufgebaut werden.
(i) Die Kanten des Baumes sind mit Zeichen aus Σ markiert.
(ii) Für jeden Knoten k des Baums und jedes Zeichen c ∈ Σ gibt es
höchstens eine Kante, die von k ausgeht und mit c markiert ist.
Für einen Knoten k in einem Trie bezeichnet path(k) den String, der sich
aus der Folge der Kantenmarkierungen auf dem Pfad von der Wurzel
nach k ergibt.
Für eine Menge P von Strings bezeichnet T rie(P ) den kleinsten Trie
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
65
• Die Größe von T rie(P ) ist linear in der Gesamtlänge der Strings von
P.
• Es sei w ein beliebiger String. Dann kann mit Hilfe von T rie(P ) in
O(|w|) geprüft werden, ob w ∈ P gilt.
• Für jeden Trie gilt: Ausgangsgrad ≤ |Σ|.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
67
2. Suffix-B¨
aume
Trie
• Ist das Pattern erschöpft und
der aktuelle Knoten markiert
einen String aus P , so ist das
Suchpattern in P .
Trie
Suffix-Trie
Beispiel 2.2. Suche des Strings
ba in dem Trie für die Menge P =
{ab, ba, babb, bb}.
• Man folgt ausgehend von der
Wurzel sukzessive den Kanten
des Tries, die mit dem Symbol
pat[j] markiert sind.
2. Suffix-B¨
aume
a
b
b
a
Definition 2.2. Es sei s = s[1] . . . s[n − 1]$ ein String. Dann ist der
Suffix-Trie ST (s) der Baum
b
b
ST (s) = T rie({s[1 . . . n], s[2 . . . n], . . . , s[n − 1 . . . n], $})
b
wobei die Blätter p von ST (s) zusätzlich eine Markierung label(p) tragen, für die gilt:
label(p) = i ⇐⇒ path(p) = s[i . . . n]
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
68
Trie
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
70
2. Suffix-B¨
aume
Trie
• Ein erster Lösungsansatz besteht darin, sämtliche Suffixe eines Textes mit Hilfe eines Tries darzustellen.
a
b
c
$
7
• Allgemein kann ein Suffix von text Präfix eines anderen Suffixes von
text sein. Dies würde dazu führen, daß nicht jeder Suffix mit einem
Blatt des Tries assoziiert werden kann.
• Deshalb wird die zusätzliche Voraussetzung eingeführt, daß text mit
einem Sonderzeichen $ abgeschlossen sein muß, das ansonsten in
text nicht vorkommt.
b
a
c
$
6
a
c
Beispiel 2.3. [Suffix-Trie] Der
Suffix-Trie für den String abcabc$
sieht folgendermaßen aus:
$
b
5
a
$
b
c
4
c
b
$
3
$
c
2
$
1
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
69
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
71
2. Suffix-B¨
aume
Trie
• Es besteht eine Eins-zu-eins-Beziehung zwischen den Knoten von
ST (s) und den verschiedenen Substrings von s.
¨
Positionsbaume
2. Suffix-B¨
aume
Bemerkungen:
• u = erfüllt Bedingung (i) für jedes s ∈ Σ+ und jedes i mit 1 ≤ i ≤ |s|.
• Die Anzahl der Knoten von ST (s) ist u.U. quadratisch in |s|.
• Für |s| ≥ 2 erfüllt u = Bedingung (ii) nicht.
• Dies ist z.B. für Strings der Form ambm$ der Fall. Solche Strings der
Länge 2m + 1 haben m2 + 4m + 2 verschiedene Substrings.
• Nicht für alle s und alle i existiert ein Positionsidentifikator.
☞ Statt einen kompletten Suffix ab Position i in text nimmt man nur
einen String auf, der die Position i in text eindeutig beschreibt.
• Falls für String s und Position i ein Positionsidentifikator existiert, so
ist er eindeutig bestimmt.
Lemma 2.1. Bei Abschluß von s mit einem Sonderzeichen $, das in s
nicht vorkommt, existiert für jede Position von s$ ein Positionsidentifikator.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
72
¨
Positionsbaume
2. Suffix-B¨
aume
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
74
¨
Positionsbaume
2. Suffix-B¨
aume
Beispiel 2.4. Der String s = abcabc$ hat die Positionsidentifikatoren:
Positionsidentifikator
i
1
2
3
4
5
6
7
Definition 2.3. Es seien Σ ein Alphabet, s, u Zeichenreihen (Strings)
∈ Σ∗ mit s 6= und i ∈ IN mit 1 ≤ i ≤ |s|.
Dann heißt u Positionsidentifikator für die Position i in s (Bezeichnung:
u = pids(i)) genau dann, wenn die folgenden Bedingungen gelten:
(i) ∃y, z mit s = yuz und |y| = i − 1.
pids(i)
abca
bca
ca
abc$
bc$
c$
$
Korollar 2.2. s1 . . . sn+1 besitzt je einen Positionsidentifikator für i =
1, . . . , n + 1 ⇐⇒ sn+1 6∈ {s1, . . . , sn}
(ii) ∀y 0, z 0 : s = y 0uz 0 ⇒ y 0 = y und z 0 = z
(iii) |u| ist minimal unter den Bedingungen (i) und (ii).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
73
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
75
¨
Positionsbaume
2. Suffix-B¨
aume
Lemma 2.3. Kein Positionsidentifikator ist Anfang (Präfix) eines Positionsidentifikators für eine weitere Position in demselben String s$.
¨
Positionsbaume
2. Suffix-B¨
aume
Beispiel 2.5. Der Positionsbaum für s = abcabc$ sieht wie folgt aus:
Beweis.
a
b
c
$
• Sei i 6= j mit p(i) Anfang von p(j),
7
b
• d.h. p(i)ω = p(j),
a
c
3
⇒ p(i) kommt in s auch an Position j vor.
c
⇒ p(i) identifiziert die Position i nicht eindeutig.
a
a
$
2
5
$
6
$
⇒ Widerspruch.
1
4
2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
76
¨
Positionsbaume
2. Suffix-B¨
aume
Positionsbaum
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
78
¨
Positionsbaume
Lemma 2.4. Jeder String s$ hat einen eindeutigen Positionsbaum.
Beweis.
Definition 2.4. Es sei s = s[1] . . . s[n]$ ein String. Dann ist der Positionsbaum P T (s) der Baum
P T (s) = T rie({pids(1), pids(2), . . . , pids(n + 1)})
• Für jede Position i gibt es einen eindeutigen Positionsidentifikator
p(i).
• Man braucht nun nur den Trie zu p(1), . . . , p(n + 1) aufzubauen.
wobei die Blätter p von P T (s) zusätzlich eine Markierung label(p) tragen, für die gilt:
• Die Eindeutigkeit folgt aus der Minimalität des Baumes.
2
label(p) = i ⇐⇒ path(p) = pids(i)
Korollar 2.5. Ein Positionsbaum für s$ mit |s| = n hat n + 1 Blätter.
Beweis. Folgt direkt aus Lemma 2.4. 2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
77
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
79
2. Suffix-B¨
aume
¨
Positionsbaume
Lemma 2.6. Es sei s 6= . Dann hat jedes Blatt im Positionsbaum von
s$ mindestens einen Bruder.
2. Suffix-B¨
aume
¨
String-Matching mit Positionsbaumen
Der Abstieg terminiert, falls:
Beweis.
(1) pat erschöpft und zwar
• p(i) = ya, y ∈ Σ∗, a ∈ Σ
(1.1) an einem inneren Knoten oder
(1.2) an einem Blatt
• Falls y = , so hat das mit i markierte Blatt einen Bruder, weil es
noch mindestens eine weitere Position im Baum gibt.
(2) pat nicht erschöpft, aber der Positionsbaum ist erschöpft und zwar
(2.1) an einem inneren Knoten oder
(2.2) an einem Blatt
• Also sei |y| ≥ 1.
⇒ Dann kommt y noch an anderer Stelle, etwa j 6= i, im String s vor
(wegen der Minimalität von p(i)).
⇒ Also muß es eine Bruderkante geben, die den Anfang des Weges zu
dem mit j markierten Blatt bildet.
2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
80
¨
String-Matching mit Positionsbaumen
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
82
¨
String-Matching mit Positionsbaumen
Aus diesen unterschiedlichen Fällen der Terminierung ergeben sich folgende Resultate:
String-Matching mit Hilfe von Positionsbäumen
(1) pat kommt genau an den Positionen vor, die vom Abbruchknoten aus
erreichbar sind.
• Gegeben sei der Positionsbaum für text$.
Insbesondere kommt im Fall (1.2) pat genau an der Position vor, mit
der das Blatt markiert ist.
• Es sei pat = p1, . . . , pm.
• Steige im Positionsbaum ab gemäß pat, d.h.
(2.1) pat kommt in text nicht vor.
– wähle zunächst die von der Wurzel ausgehende und mit p1 markierte Kante,
– dann die mit p2 markierte Kante, usw.
(2.2) pat kommt höchstens an der Position vor, mit der das erreichte Blatt
markiert ist.
• Es treten nun verschiedene Fälle auf, die den Abstieg beenden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
81
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
83
¨
String-Matching mit Positionsbaumen
2. Suffix-B¨
aume
Beispiel 2.6. Es
abcabc.
sei
text
=
• pat = bc: Fall 1.1, pat kommt
genau ab den Stellen 2 und 5
vor.
• pat = bcaa: Fall 2.2, pat kann
höchstens an Position 2 vorkommen. Prüfung ergibt: pat
kommt nicht vor.
a
b
• pat = ca: Fall 1.2, pat kommt
nur an der Stelle 3 vor.
¨
String-Matching mit Positionsbaumen
• Der Aufwand für das Preprocessing (Konstruktion des Positionsbaums) wurde bisher nicht berücksichtigt.
• Selbst ein hoher Preprocessingaufwand würde sich aber u.U. lohnen,
wenn:
– genügend Anfragen an text gestellt werden oder
– wenn der Aufwand zu verschiedenen Zeiten verschieden teuer ist.
$
7
b
• pat = ac: Fall 2.1, pat kommt in
text nicht vor.
• pat = cab: Fall 2.2, pat kann
höchstens an Position 3 vorkommen. Prüfung ergibt: pat
kommt vor.
c
2. Suffix-B¨
aume
a
c
3
c
a
1
a
$
2
5
$
6
$
4
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
84
¨
String-Matching mit Positionsbaumen
Komplexität:
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
86
¨
Konstruktion von Positionsbaumen
Ansätze zur Konstruktion von Positionsbäumen
• Der Aufwand für die Suche beträgt O(|pat|),
• mit Ausnahme von Fall 1.1, wo ein Unterbaum traversiert werden
muß.
• Es liegt die Vermutung nahe, daß im Falle 1.1 der Aufwand O(|pat| +
k) beträgt, wobei k die Anzahl der Vorkommen von pat ist.
• Alternative: man ermittelt für jeden Knoten (oder jeden ab einer gewissen Tiefe) die Marken der von diesem Knoten aus erreichbaren
Blätter und legt diese als Liste in dem Knoten ab.
Nachteil: erhöhter Speicherplatzverbrauch
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
85
Grundlegender Ansatz: Induktive Konstruktion, d.h. man konstruiert
sukzessive P T (s1), . . . , P T (s1, . . . si), P T (s1 . . . sisi+1), . . . , P T (s1 . . . sn$).
Problem: Die Zwischenbäume P T (s1 . . . si) brauchen nicht zu existieren.
Beispiel: s = abab$.
P T (s1s2s3) existiert nicht, da Position 3 keinen Pos.-Id. in aba hat.
Wie kann man diese Schwierigkeiten umgehen?
(a) Man konstruiert den Baum von rechts nach links (anstatt von links
nach rechts), d.h.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
87
2. Suffix-B¨
aume
¨
Konstruktion von Positionsbaumen
P Tn+1 = P T ($)
P Tn = P T (sn$)
P Tn−1 = P T (sn−1sn$)
..
P Ti = P T (si . . . sn$)
..
P T1 = P T (s1 . . . sn$)
Bemerkung: Für jeden Teilstring si . . . sn$ existiert der zugehörige Positionsbaum.
Ausgehend von dem Positionsbaum für si . . . sn$ konstruiert man den
Positionsbaum für si−1si . . . sn$ wie folgt:
Von der Wurzel aus durchläuft man einen Pfad mit den Markierungen
si−1, si, . . ., bis man:
P T (s1$)
P T (s1s2$)
..
P T (s1s2 . . . sn$)
(a) ein Blatt k erreicht.
– Das Blatt k sei mit j markiert.
– Der bisherige Positionsidentifikator für j kommt also auch an der
Stelle i − 1 vor.
Nachteil: sehr hoher Aufwand
2. Suffix-B¨
aume
88
¨
Konstruktion von Positionsbaumen
(c) Man spiegelt den Text und die Definition des Begriffs Pos.-Id. und
geht wie unter (a) vor.
Nachteil: unnatürliche Umgehensweise
(d) Man verzichtet darauf, daß die Zwischenbäume Positionsbäume
sind.
☞ Wir untersuchen die Ansätze (a) und (d).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
90
¨
Konstruktion von Positionsbaumen
– Sowohl p(j) als auch p(i − 1) sind zu verlängern, bis sie sich unterscheiden.
– Dementsprechend wird der Pfad von dem erreichten Blatt aus
verlängert.
– Es entstehen zwei neue Blätter mit den Markierungen i − 1 und j.
(b) einen inneren Knoten k erreicht, von dem aus keine Kante mit der
benötigten Markierung ausgeht.
– Es ist ein neues Blatt k 0 an k anzuhängen.
– Dieses Blatt erhält die Markierung i − 1.
– Die Kantenmarkierung zur Kante (k, k 0) ist das letzte Zeichen von
p(i − 1).
• (a) : Rechts-Links-Konstruktion
• (b) : Links-Rechts-Konstruktion
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
¨
Konstruktion von Positionsbaumen
Rechts-Links-Konstruktion von Positionsbäumen
(b) Man hängt jeweils ein $-Zeichen an, d.h.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
89
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
91
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
• Ein Positionsbaum wächst also von einem Blatt aus weiter nach unten,
Veranschaulichung für (a):
PT(bcabc$)
PT(abcabc$)
a
b
c
$
a
b
c
– bis sich eine Unterscheidung der Positionsidentifikatoren ergibt
– und der Pfad sich in zwei Blätter aufspaltet,
$
7
4
$
2
5
b
6
3
c
a
1
a
$
2
5
• oder von einem Zwischenknoten wächst ein neues Blatt heraus.
$
a
c
6
3
a
7
$
a
c
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
Aufwandsabschätzung:
• Der Gesamtaufwand zur Konstruktion eines Positionsbaums für
einen String der Länge n ist:
$
4
O(
n
X
|p(i)|)
i=1
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
92
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
PT(bcabc$)
PT(bbcabc$)
b
c
$
a
7
4
a
c
3
¨
Konstruktion von Positionsbaumen
b
c
• Nachteil der Rechts-Links-Konstruktion: Die gesamte Zeichenreihe
muß bekannt sein, bevor sich der Positionsbaum konstruieren läßt.
$
7
4
b
$
6
2. Suffix-B¨
aume
94
Bemerkungen:
Veranschaulichung für (b):
a
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
a
c
3
1
a
$
a
$
2
5
2
5
$
• Beim Entwickeln von Text möchte man aber u.U. schon vorher Textstellen identifizieren und Korrekturen vornehmen.
6
• Einen Positionsbaum für den umgekehrten Text aufzubauen wäre unnatürlich.
• Kann ein Positionsbaum auch effizient von links nach rechts konstruiert werden?
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
93
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
95
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
• Für Positionsbäume gilt eine sehr einfache und wichtige Verschachtelungseigenschaft, die beschreibt, wie sich Positionsidentifikatoren
überlappen können.
Links-Rechts-Konstruktion von Positionsbäumen
• Ziel ist es, ein sogenanntes on-line Verfahren für die Konstruktion von
Positionsbäumen zu entwickeln.
• Da für Teilstrings der Positionsbaum nicht existiert, muß man partielle
Positionsbäume betrachten.
• Die wesentliche Aussage hierzu liefert das folgende MonotonieLemma.
Lemma 2.7. [Monotonie-Lemma] Es sei e(i) die Position, bei der der
Positionsidentifikator p(i) endet. Dann gilt:
• Ein partieller Positionsbaum enthält für genau diejenigen Positionen
des Textes einen Positionsidentifikator, für die es einen solchen Positionsidentifikator gibt.
i<j
=⇒
e(i) ≤ e(j)
Beweis. Annahme: Es gibt in einem String s Positionen i < j mit e(i) >
e(j).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
96
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
Beispiel 2.7. Der partielle Positionsbaum für abba sieht wie folgt aus:
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
98
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
Veranschaulichung:
s
a
i
b
b
a
j
e(j)
e(i)
• p(i) = si . . . se(i) ist der kürzestmögliche String, der die Position i
eindeutig bestimmt.
b
• Somit kommt si+1 . . . se(i)−1 noch an anderer Stelle vor.
1
3
2
• sj . . . se(j) ist Substring von si+1 . . . se(i)−1.
• Somit ist sj . . . se(j) nicht eindeutig in s. Widerspruch.
2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
97
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
99
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
• Wir fassen Intervalle von Positionen zusammen, deren Pos.-Id. an
derselben Stelle enden. Dies deuten wir so an:
2. Suffix-B¨
aume
¨
Konstruktion von Positionsbaumen
Konstruktionsschritt:
• Bei der Hinzunahme von si+1 wird nun versucht, die Markierung k
im partiellen Positionsbaum weiter nach unten zu verschieben.
text
Intervalle von
• Hierbei können die folgenden Fälle auftreten:
die hier
enden
Positionen
• Graphisch dargestellt ergibt sich dann die folgende Verschachtelung
für die Positionsidentifikatoren:
text
$
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
100
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
Prinzip der Links-Rechts-Konstruktion
• Man nehme an, wir haben den partiellen Positionsbaum für den
String s1 . . . si.
• k sei die erste Postion, für die kein Positionsidentifikator existiert, d.h.
sk sk+1 . . . si ist nicht eindeutig in s1 . . . si.
s(1)s(2) . . .
s(k−1) s(k) . . .
s(i)
• Der Anfang von p(k) ist sk sk+1 . . . si.
(1) Der mit k markierte Knoten verfügt über eine ausgehende Kante
für si+1.
Dann bewegt man k längs der mit si+1 markierten Kante. Jetzt
können die folgenden Fälle auftreten:
(1.1) Der jetzt mit k markierte Knoten ist ein innerer Knoten.
Dann ist nichts weiter zu tun.
(1.2) Der jetzt mit k markierte Knoten ist ein Blatt mit Markierung l.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
102
¨
Konstruktion von Positionsbaumen
Dann ist p(l) um ein Zeichen zu verlängern, d.h. an das bisherige Blatt wird ein neuer Knoten angehängt und die Markierung l
wandert zu dem neuen Blatt.
(2) Der mit k markierte Knoten hat keine ausgehende Kante, die mit
si+1 markiert ist.
Dann wird ein neues Blatt und eine neue ausgehende und mit si+1
markierte Kante zu diesem Blatt angelegt.
Das neue Blatt wird mit k markiert.
Es gilt nun zu prüfen, ob Positionsidentifikatoren für die Positionen
k + 1, k + 2, . . . existieren. Hierzu sind neue Blätter in den Baum
einzutragen.
Es sei k + m die erste Position für die nun kein Pos.-Id. existiert.
Dann ist noch k + m einzutragen.
• Diesem Anfang entspricht ein Knoten im partiellen Positionsbaum.
Dieser Knoten sei mit k markiert.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
101
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
103
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
Fall 1.1:
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
Fall 2:
s(i)
s(i)
s(i)
s(i)
k
k
s(i+1)
s(i+1)
s(i+1)
k
k
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
104
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
Fall 1.2:
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
106
¨
Konstruktion von Positionsbaumen
Bemerkungen:
• Man kann den Eingabestring jederzeit mit einem $ abschließen.
Dann wird mit dem angegebenen Verfahren der zugehörige Positionsbaum fertig konstruiert.
s(i)
• Folgende Kosten treten bei der Konstruktion auf:
s(i)
(1.1) p(k) wird um ein Zeichen verlängert.
Aufwand: O(1)
(1.2) p(k) und p(l) werden um je ein Zeichen verlängert.
Aufwand: O(1)
(2) p(k) wird um ein Zeichen verlängert.
Aufwand: O(1)
Das Einfügen von k + 1, k + 2, . . . k + m − 1 und das Auffinden von
k + m kostet proportional zur Länge von p(k + 1) . . . p(k + m).
k
s(i+1)
l
s(i+1)
k
s( e(l) )
l
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
105
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
107
¨
Konstruktion von Positionsbaumen
2. Suffix-B¨
aume
• Der Gesamtaufwand zum Aufbau eines Positoinsbaums für einen
String der Länge n ist also:
O(
n
X
|p(i)|)
i=1
• Damit ist die Links-Rechts-Konstruktion nicht aufwendiger als die
Rechts-Links-Konstruktion.
• Sprachliche Texte s haben häufig die Eigenschaft, daß |p(i)| ≈ log |s|
gilt. Dann ergibt sich für den Gesamtaufwand:
2. Suffix-B¨
aume
Suffix-B¨
aume
Definition 2.5. [Suffix-Baum] Es sei s = s[1] . . . s[n − 1]$ ein String.
Dann ist der Suffix-Baum (suffix tree) SB(s) der Baum, der aus dem
Suffix-Trie ST (s) auf die folgende Weise entsteht:
(i) Jede Kantenfolge π, die nur aus Knoten mit Ausgangsgrad eins besteht, wird zu einer Kante e komprimiert. Es sei path0(π) der String,
der sich aus Konkatenation der Kantenmarkierungen von π ergibt.
(ii) Die Kante e erhält die Markierung label(e) = (i, j) mit path0(π) =
s[i . . . j].
O(|s| log |s|)
• Im Worst-Case beträgt der Aufwand O(n2).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
108
Suffix-B¨
aume
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
110
2. Suffix-B¨
aume
Suffix-B¨
aume
Beispiel 2.8. [Suffix-Baum] Der Suffix-Baum für s = abcabc$ sieht wie
folgt aus:
Suffix-Bäume
abc
Suffix-Bäume entstehen aus Suffix-Tries,
(1,3)
• indem Pfade nicht nur wie beim Positionsbaum von den Blätter her
kompaktifiziert werden,
• sondern sämtliche Teilpfade, die nur Knoten mit genau einem Sohn
enthalten, auf eine Kante reduziert werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
bc
109
abc$
(4,7)
1
c
$
(3,3)
(2,3)
(7,7)
7
abc$
$
(7,7) (4,7)
4
2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
$
abc$
(7,7) (4,7)
5
3
$
(7,7)
6
111
2. Suffix-B¨
aume
Suffix-B¨
aume
Bemerkungen:
• Kanten, die von dem gleichen Knoten ausgehen, unterscheiden sich
im ersten Symbol der Markierung.
• Somit ist bei einer Suche für das Branching, d.h. der Entscheidung,
welchem Pfad man folgen soll, nur ein Zeichenvergleich erforderlich.
• Alle internen Knoten haben einen Ausgangsgrad ≥ 2.
Eine wesentliche Eigenschaft von Suffix-Bäumen ist, daß ihre Größe
linear in der Länge des zugehörigen Strings ist.
2. Suffix-B¨
aume
112
Suffix-B¨
aume
Lemma 2.8. Es sei text ein String. Dann ist die Anzahl der Knoten von
SB(text) gegeben durch O(|text|).
Satz 2.9. Gegeben sei ein String text. Liegt der Suffix-Baum SB(text)
vor, dann kann in Zeit O(|text|) ein Preprocessing von SB(text) erfolgen, so daß die folgenden Anfragen für beliebige Strings w in Zeit
O(|w|) beantwortet werden können:
(i) Man finde das erste Vorkommen von w in text.
(ii) Man finde das letzte Vorkommen von w in text.
Weiterhin können sämtliche Vorkommen von w in text in Zeit O(|w| + k)
aufgelistet werden, wobei k die Anzahl der Vorkommen von w in text
ist.
Beweis: Zu den Anfragen (i) bis (iii):
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
114
Suffix-B¨
aume
• Das Preprocessing erfolgt bottom-up.
• In jedem Knoten v werden die Werte für das erste Vorkommen
f irst(v), das letzte Vorkommen last(v) und die Anzahl der Vorkommen count(v) des zugehörigen Strings path(v) abgelegt.
Beweis. Es sei n = |text|.
• ST (text) hat n Blätter.
• In einem Blatt ist die Anzahl der Vorkommen gleich eins. Das erste
und letzte Vorkommen ergibt sich durch die Knotenmarkierung.
• Somit hat auch SB(text) n Blätter.
• Da jeder innere Knoten von SB(text) einen Ausgangsgrad ≥ 2 hat,
hat SB(text) höchstens n − 1 innere Knoten.
• Somit hat SB(text) insgesamt höchstens 2n − 1 Knoten.
2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Suffix-B¨
aume
(iii) Man ermittle die Anzahl der Vorkommen von w in text.
• Interne Knoten repräsentieren Substrings, die die größten gemeinsamen Präfixe zweier Suffixe sind.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
113
• In einem inneren Knoten gilt:
– Das erste Vorkommen ist gleich dem Minimum der Werte für f irst
der Söhne.
– Das letzte Vorkommen ist gleich dem Maximum der Werte für last
der Söhne.
– Die Anzahl der Vorkommen ist gleich der Summe der Werte für
count der Söhne.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
115
2. Suffix-B¨
aume
Suffix-B¨
aume
⇒ Für einen String w kann die Antwort zu den ersten drei Fragen durch
eine Top-Down-Suche in Zeit O(|w|) berechnet werden.
2. Suffix-B¨
aume
Suffix-B¨
aume
Satz 2.10. Ein Suffix-Baum für einen String text kann in Zeit O(|text|)
aufgebaut werden.
Beweis. Siehe Literatur, z.B. mit dem Algorithmus von McCreight. 2
Um alle Vorkommen von w zu ermitteln, geht man wie folgt vor:
• Der zu w zugehörige Knoten v wird in Zeit O(|w|) ermittelt.
• Von Knoten v aus wird der Baum traversiert, um alle Vorkommen zu
ermitteln.
• Wenn k die Anzahl der Vorkommen von w in text ist, dann hat der
Unterbaum mit Wurzel v genau k Blätter.
• Mit der gleichen Argumentation wie in Lemma 4.2 folgt, daß der Unterbaum mit Wurzel v insgesamt höchstens 2k − 1 Knoten hat.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
116
2. Suffix-B¨
aume
Suffix-B¨
aume
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
• Somit ist die Traversierung des Unterbaums in O(k) möglich.
⇒ Der Gesamtaufwand beträgt O(|w| + k).
2
Das Problem des exakten String-Matchings wird wie folgt verallgemeinert: statt eines einzelnen Musters ist nun eine Menge von Mustern
gegeben.
Anfragepfad zu w
Problem 2.1. [Matching von Wortmengen] Gegeben sei eine Menge
P = {pat1, . . . , patk } von Strings und ein String text. Man bestimme, ob
für ein i (mit 1 ≤ i ≤ k) pati ein Substring von text ist.
first(v) = erstes Vorkommen von w
Preprocessing
last(v) = letztes Vorkommen von w
count(v) = Anzahl der Vorkommen von w
v
Bemerkungen:
• Im folgenden bezeichnet m :=
Strings in P .
Unterbaum mit Wurzel v
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Matching von Wortmengen
Matching von Wortmengen
Veranschaulichung des Retrievals:
Bottom-up
118
117
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Pk
i=1 |pati|
die Gesamtlänge der
119
2. Suffix-B¨
aume
Matching von Wortmengen
2. Suffix-B¨
aume
Matching von Wortmengen
• Durch k-fache Anwendung des Algorithmus von Knuth, Morris Pratt
bzw. Boyer-Moore kann Problem 2.1 in Zeit O(m+kn) gelöst werden.
• Liegt der Automat für einen String pat vor, kann in O(n) geprüft werden, ob text in pat vorkommt.
• Im folgenden wird gezeigt, daß Problem 2.1 in Zeit O(m + n) und
Platz O(m) lösbar ist.
• Der zugehörige Algorithmus simuliert hierzu einfach die Abarbeitung
des Automaten.
Grundidee zur Lösung von Problem 2.1:
• wesentlicher Nachteil: i. allg. hat solch ein Automat O(|Σ|m) Zustandsübergänge.
☞ Man konstruiere einen deterministischen endlichen Automaten, der
die Strings aus P erkennt.
Dieser automatenbasierte Ansatz wird nun auf eine Menge von Strings
verallgemeinert.
☞ Genauer: Man baue einen Automaten für die Sprache
Σ∗{pat1, . . . , patk }Σ∗
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
120
2. Suffix-B¨
aume
Matching von Wortmengen
Veranschaulichung: Für Σ = {a, b} und P = {abaaba} kann der folgende Automat verwendet werden:
b
0
a
a
a
b
1
2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
122
Matching von Wortmengen
Aho-Corasick Pattern-Matching-Automat
a
a
3
a
4
b
5
a
Definition 2.6. Ein Aho-Corasick Pattern-Matching-Automat (ACAutomat) besteht aus den folgenden Komponenten:
6
b
b
(i) Einer endlichen Menge Q von Zuständen,
b
(ii) einem endlichen Eingabealphabet Σ,
b
Bemerkungen:
(iii) einer Transitionsfunktion g : Q × Σ −→ Q ∪ {f ail},
• pat = abaaba ist genau dann in text enthalten, wenn bei Anwendung
des obigen Automaten auf text irgendwann der Zustand 6 erreicht
wird.
(iv) einer Fehlerfunktion h : Q −→ Q ∪ {f ail},
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
121
(v) einem initialen Zustand q0 ∈ Q und
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
123
2. Suffix-B¨
aume
Matching von Wortmengen
(vi) einer Menge F ⊂ Q von Endzuständen.
2. Suffix-B¨
aume
Matching von Wortmengen
Beispiel 2.9. [AC-Automat f ür einelementiges P ] Es sei P = {abaaba}.
Der AC-Automat sieht dann folgendermaßen aus:
Solch ein AC-Automat wird wie folgt zur Lösung von Problem 2.1 eingesetzt:
0
a
1
b
2
a
3
a
4
b
5
a
6
Algorithmus 2.1. [Algorithmus von Aho-Corasick]
q := q0
for i := 1 to n do
while q 6= f ail and g(q, text[i]) = f ail do q := h(q) end
if q = f ail then q := q0 else q := g(q, text[i]) endif
if q ∈ F then return true
end
return false
Transitionsfunktion g
Fehlerfunktion h
Bemerkungen:
• Die Fehlerfunktion h entspricht der Tabelle border aus dem Algorith-
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
124
Matching von Wortmengen
Bemerkungen:
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
126
Matching von Wortmengen
mus von Morris und Pratt.
• Für jedes Symbol von text wird zunächst versucht, der Transitionsfunktion g zu folgen.
• Ist dies nicht möglich, wird die Fehlerfunktion h angewendet, bis ein
Zustandsübergang möglich ist.
• Durch die Fehlerfunktion ist die Größe des AC-Automaten O(m) und
somit unabhängig von |Σ|.
Die meisten Komponenten eines AC-Automaten ergeben sich aus dem
Trie für die Menge P .
Konsequenzen für die Konstruktion des AC-Automaten für P :
• Findet man auch mit h keinen möglichen Zustandsübergang, beginnt
man wieder von vorne.
• Die Zustandsmenge Q entspricht den Knoten von T rie(P ).
• q0 ist die Wurzel von T rie(P ).
• Die Transitionsfunktion g ergibt sich aus den Kanten von T rie(P )
und der Bedingung: g(q, c) = f ail genau dann, wenn keine mit c
markierte Kante von dem Knoten q ausgeht.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
125
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
127
2. Suffix-B¨
aume
Matching von Wortmengen
2. Suffix-B¨
aume
Matching von Wortmengen
• Die Endzustände ergeben sich aus der folgenden Bedingung:
1
a
q ∈ Q ist genau dann ein Endzustand, wenn ein pat ∈ P existiert mit
pat ist Suffix von path(q).
b
2
(i) Jedes Blatt von T rie(P ) ist ein Endzustand.
(Beispiel: Knoten 3)
(ii) Jeder innere Knoten q mit path(q) ∈ P ist ein Endzustand.
Solche Endzustände treten auf, wenn ein pati ∈ P echter Präfix
eines patj ∈ P ist.
(Beispiel: Knoten 5)
(iii) Jeder innere Knoten q für den ein pat ∈ P existiert mit pat ist echter
Suffix von path(q) ist ein Endzustand.
Solche Endzustände treten auf, wenn ein pati ∈ P Substring und
nicht echter Suffix oder Präfix eines patj ∈ P ist.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
4
b
Genauer: es ist gibt drei disjunkte Klassen von Endzuständen:
128
Matching von Wortmengen
a
3
5
b
8
b
6
Transitionsfunktion g
b
Fehlerfunktion h
7
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
130
Matching von Wortmengen
Bemerkungen:
Anders ausgedrückt: pati tritt im Innern von patj auf.
(Beispiel: Knoten 6)
Die Endzustände, die unter (i) oder (ii) fallen, können beim Aufbau
von T rie(P ) direkt erkannt werden.
• Die Fehlerfunktion stellt die Verallgemeinerung von border auf eine
Menge von Strings dar.
Es bleibt das Problem, die Fehlerfunktion h zu berechnen und Endzustände der Klasse (iii) zu erkennen.
• Durch die Maximalität in der Definition der Fehlerfunktion wird sichergestellt, daß kein Vorkommen eines Musters übersehen wird (entspricht der kleinsten Verschiebung).
Die Fehlerfunktion h des AC-Automaten wird wie folgt definiert:
h(q) = q 0 gilt genau dann, wenn q 0 unter den Knoten von T rie(P ) den
längsten echten Suffix von path(q) liefert. Falls kein solches q 0 existiert,
gelte h(q) = f ail.
• Die Fehlerfunktion geht im Baum stets nach oben.
Algorithmus 2.2. [Berechnung der Fehlerfunktion eines AC-Automaten]
Beispiel 2.10. [Fehlerfunktion eines AC-Automaten] Es sei P
{ab, ba, babb, bb}.
=
h(q0) := f ail
forall q mit q ist Sohn von q0 do h(q) := q0 end
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
129
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
131
2. Suffix-B¨
aume
0
Matching von Wortmengen
2. Suffix-B¨
aume
0
d.h., path(q) entspricht dem längsten Präfix eines Patterns aus P ,
der mit einem Suffix des bisher gelesenen Teils von text (nämlich
text[1 . . . i]) übereinstimmt.
– Es sei i die erste Position von text, an der ein Vorkommen eines
Strings aus P endet.
Von den Strings aus P , die an i enden, sei patj der längste.
i0 ≤ i sei die Position, an der patj beginnt.
q sei der Zustand des AC-Automaten nach der Bearbeitung von
text[i].
– Man kann zwei Fälle unterscheiden:
(i): Es existiert i00 < i0 mit text[i00 . . . i] ist echter Präfix eines Patterns patj 00 aus P . Falls mehrere solche i00 existieren, betrachte
man deren Maximum.
Es sei l := i − i00 + 1 die Länge des zu patj 00 gehörigen Präfixes. Aus der Invariante und der Maximalität von i00 folgt: path(q) =
patj 00 [1 . . . l].
forall q mit depth(q ) ≥ 2 in BFS-Reihenfolge do
q sei der Vater von q 0
c sei das Symbol mit g(q, c) = q 0
r := h(q)
while r 6= f ail and g(r, c) = f ail do
r := h(r)
end
if r = f ail then
h(q 0) := g(q0, c)
else
h(q 0) := g(r, c)
if h(q 0) ist Endzustand then
nimm q 0 in die Menge der Endzustände auf
endif
endif
end
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
Matching von Wortmengen
132
Matching von Wortmengen
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
2. Suffix-B¨
aume
134
Matching von Wortmengen
Nach Konstruktion ist patj in patj 00 enthalten, und somit ist q ein
Endzustand der Klasse (iii).
(ii): Gilt (i) nicht, dann ist gemäß der Invariante patj der längste
erkannte Präfix, und q ist ein Endzustand der Klasse (i) oder (ii).
Lemma 2.11. Algorithmus 2.10 berechnet die Fehlerfunktion eines
AC-Automaten in Zeit O(m).
Satz 2.12. Problem 2.1 kann mit dem Algorithmus von Aho-Corasick
in Zeit O(n + m) und Platz O(m) gelöst werden.
• Laufzeit und Platz
Beweis.
– Preprocessing in O(m).
– Platz wird nur für den Trie benötigt.
– Die Transitionsfunktion g wird höchstens n mal erfolgreich angewendet.
– Bei jeder erfolgreichen Anwendung von g geht man im Trie um
genau eine Stufe nach unten.
– Die Fehlerfunktion h geht im Baum stets nach oben.
– Somit kann h höchstens n mal angewendet werden.
• Korrektheit
– Gemäß der Definition der Fehlerfunktion h gilt in Algorithmus 2.9
am Ende der Schleife:
path(q) = text[i − depth(q) + 1 . . . i]
und
depth(q) = max{ l |patj [1 . . . l] = text[i − l + 1 . . . i] (1 ≤ j ≤ k)}
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
133
2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
135
¨ Ausdr ¨ucke
Matching regularer
3. Approximatives String-Matching
3 Matching regulärer Ausdrücke und approximatives
String-Matching
¨ Ausdr ¨ucke
Matching regularer
3. Approximatives String-Matching
Vorgehensweise:
• Aus r wird ein nichtdeterministischer endlicher Automat (NEA) mit
-Übergängen konstruiert.
Statt einer endlichen Anzahl von Mustern möchte man eventuell ein
Musterschema vorgeben. Zur Spezifikation von Musterschemata eignen sich reguläre Ausdrücke.
Problem 3.1. [Matching regulärer Ausdr ücke] Gegeben seien ein
regulärer Ausdruck r und ein String text. L(r) bezeichne die durch r
definierte Sprache.
Man bestimme, ob ein Substring s von text existiert mit s ∈ L(r).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
–
–
–
–
bei dem die Knoten die Zustände darstellen,
jede Kante mit einem Symbol aus Σ ∪ {} markiert ist,
ein Zustand als initialer Zustand ausgezeichnet ist und
einige Zustände Endzustände sind.
• Ein NEA akzeptiert einen String, wenn ein Pfad vom initialen Zustand
zu einem Endzustand existiert, für den die Konkatenation der beteiligten Kanten den String ergibt.
136
¨ Ausdr ¨ucke
Matching regularer
3. Approximatives String-Matching
• Ein NEA mit -Übergängen ist ein gerichteter Graph,
• m bezeichnet im folgenden die Länge von r.
• Durch einen regulären Ausdruck ist u.U. eine unendliche Menge von
Mustern gegeben.
• Grundidee zur Lösung von Problem 3.1: Man konstruiere einen Automaten zur Erkennung der Sprache
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
138
¨ Ausdr ¨ucke
Matching regularer
3. Approximatives String-Matching
Die Konstruktion des NEA erfolgt analog zum Beweis des Satzes über
die Äquivalenz von regulären Ausdrücken und endlichen Automaten
(vgl. Satz 2.3 bei Hopcroft/Ullman).
Sie basiert auf den folgenden fünf Regeln:
(1) Für die elementaren regulären Ausdrücke ∅, und c ∈ Σ werden die
folgenden Automaten konstruiert:
Σ∗L(r)
ε
c
• Hier sind verschiedene Ansätze zur Automatenkonstruktion sinnvoll:
(i) Konstruktion eines nichtdeterministischen Automaten oder
(ii) eines deterministischen Automaten.
• Im folgenden wird nur Ansatz (i) näher untersucht.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
137
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
139
¨ Ausdr ¨ucke
Matching regularer
3. Approximatives String-Matching
(2) Aus den Automaten N1 und N2 für die regulären Ausdrücke r1 und r2
wird für r1|r2 der folgende Automat konstruiert:
N1
ε
¨ Ausdr ¨ucke
Matching regularer
Bemerkungen:
• Der nach den Regeln (1) bis (5) für r konstruierte Automat N hat
höchstens 2m Zustände, denn jede Regel erzeugt nicht mehr als
zwei neue Zustände.
ε
ε
3. Approximatives String-Matching
ε
• Die Regeln (1) bis (5) benötigen bei der Konstruktion jeweils nur konstante Zeit.
N2
• N hat genau einen Start- und genau einen Endzustand.
(3) Aus den Automaten N1 und N2 für die regulären Ausdrücke r1 und r2
wird für r1r2 der folgende Automat konstruiert:
N1
ε
N2
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
140
¨ Ausdr ¨ucke
Matching regularer
3. Approximatives String-Matching
(4) Aus dem Automaten N für den regulären Ausdruck r wird für r ∗ der
folgende Automat konstruiert:
ε
N
ε
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
142
¨ Ausdr ¨ucke
Matching regularer
• Jeder Zustand hat entweder
– genau eine ausgehende Kante, die mit einem Symbol c ∈ Σ markiert ist oder
– höchstens zwei mit markierte ausgehende Kanten.
Als Konsequenz ergibt sich das folgende Lemma.
ε
ε
Lemma 3.1. Zu einem regulären Ausdruck r kann in O(m) ein äquivalenter NEA mit -Übergängen konstruiert werden.
(5) Für den regulären Ausdruck (r) wird der Automat von r genutzt.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
• Der Startzustand hat keine eingehende Kante, und der Endzustand
hat keine ausgehende Kante.
141
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
143
¨ Ausdr ¨ucke
Matching regularer
3. Approximatives String-Matching
∗
Beispiel 3.1. Für den regulären Ausdruck (a|b) aba ergibt sich der folgende NEA:
ε
a
ε
ε
ε
ε
ε
b
a
b
a
3. Approximatives String-Matching
¨ Ausdr ¨ucke
Matching regularer
Q := eps({qstart})
if qend ∈ Q then return true
for i := 1 to n do
Q := eps(g(Q, text[i]) ∪ {qstart})
if qend ∈ Q then return true
end
return false
Lemma 3.2. Es sei r ein regulärer Ausdruck und N der zugehörige
NEA. Dann kann mit Algorithmus 3.1 in Zeit O(nm) geprüft werden, ob
ein String text einen auf r passenden Substring enthält.
ε
ε
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
144
¨ Ausdr ¨ucke
Matching regularer
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
Algorithmus 3.1. [Simulation eines NEA]
Beweis.
• Im folgenden Algorithmus bezeichnet qstart den Startzustand und
qend den Endzustand.
• N hat O(m) viele Zustände.
146
¨ Ausdr ¨ucke
Matching regularer
• Q kann über einen Bitvektor repräsentiert werden.
• Q ist eine Menge von Zuständen.
• Jeder Zustand hat höchstens zwei ausgehende Kanten.
• g(Q, c) bezeichnet die Menge aller Zustände, die von einem Zustand
∈ Q aus über eine mit c markierte Kante erreichbar sind.
⇒ g(Q, text[i]) und eps(Q) können in O(m) berechnet werden.
• eps(Q) bezeichnet alle Zustände, die von einem Zustand ∈ Q aus
über mit markierte Kanten erreichbar sind.
Aus Lemma 3.1 und Lemma 3.2 ergibt sich:
• Da das Muster an einer beliebigen Stelle des Textes auftreten kann,
wird in jeder Iteration der Startzustand qstart zur aktuellen Zustandsmenge hinzugenommen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
145
2
Satz 3.3. Problem 3.1 kann in Zeit O(nm) und Platz O(m) gelöst werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
147
3. Approximatives String-Matching
¨ Ausdr ¨ucke
Matching regularer
Ein anderer Ansatz zum Matching regulärer Ausdrücke besteht darin,
statt eines NEA einen deterministischen Automaten zu verwenden.
3. Approximatives String-Matching
String-Metriken
Anwendungsbeispiele:
• Molekularbiologie (Erkennung von DNA-Sequenzen)
Bemerkungen:
• Ein NEA kann stets in einen äquivalenten deterministischen Automaten überführt werden (siehe “Theoretische Informatik”).
• Mit einem deterministischen Automaten könnte die Erkennung eines
Musters in Zeit O(n) erfolgen.
• Problem: Die Größe eines deterministischen Automaten ist im worst
case exponentiell in m.
• Ausgleich verschiedener Schreibweisen (Grafik vs. Graphik)
• Ausgleich von Beugungen
• Toleranz gegenüber Tippfehlern
• Toleranz gegenüber OCR-Fehlern
Satz 3.4. Mit einem deterministischen Automaten kann Problem 3.1 in
Zeit O(2m + n) und Platz O(2m) gelöst werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
148
String-Metriken
Approximatives String-Matching
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
150
String-Metriken
String-Metriken
Der Begriff “nahezu” wird dabei durch eine Metrik auf Strings formalisiert.
• In den Kapiteln 1 und 2 waren die Probleme derart, daß das Muster
pat exakt mit einem Substring von text übereinstimmen mußte.
Zur Erinnerung: Sei M eine Menge. Eine Funktion d : M × M −→ IR
heißt Metrik, wenn die folgenden Bedingungen erfüllt sind:
• Beim Matching von regulären Ausdrücken ließ man zwar Varianten
zu, aber ebenfalls keine Fehler.
• d(x, y) ≥ 0 für alle x, y ∈ M
• In vielen praktischen Fällen ist es wünschenswert, die Stellen von
text zu finden, die mit pat “nahezu” übereinstimme, d.h. man erlaubt
Abweichungen zwischen pat und text.
• d(x, y) = 0 ⇔ x = y für alle x, y ∈ M
• d(x, y) = d(y, x) für alle x, y ∈ M
• d(x, z) ≤ d(x, y) + d(y, z) für alle x, y, z ∈ M .
(M, d) ist dann ein metrischer Raum.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
149
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
151
3. Approximatives String-Matching
String-Metriken
Problem 3.2. Gegeben seien ein String pat, ein String text, eine Metrik
d für Strings und ein ganze Zahl k ≥ 0.
Man finde alle Substrings y von text mit d(pat, y) ≤ k.
3. Approximatives String-Matching
String-Metriken
Editierdistanz, Levenstein-Metrik
Definition 3.2.
Bemerkungen:
• Für zwei Strings x und y ist die Editierdistanz (Edit Distance)
edit(x, y) definiert als die kleinste Anzahl an Einfüge- und Löschoperationen, die notwendig sind, um x in y zu überführen.
• Für k = 0 erhält man Problem 1.1(b).
• Problem 3.2 ist zunächst ein “abstraktes” Problem, da nichts über die
Metrik d ausgesagt wird.
• Zur Konkretisierung von Problem 3.2 und zur Entwicklung von entsprechenden Algorithmen müssen zunächst sinnvolle Metriken betrachtet werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
152
String-Metriken
• Läßt man zusätzlich auch die Ersetzung eines Symbols zu, so spricht
man von einer Levenstein-Metrik (Levenshtein Distance) lev(x, y).
• Nimmt man als weitere Operation die Transposition (Vertauschung
zweier benachbarter Symbole) hinzu, so erhält man die DamerauLevenstein-Metrik dlev(x, y).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
154
String-Metriken
Bemerkungen:
Hamming-Distanz
Definition 3.1. Für zwei Strings x und y mit |x| = |y| = m ergibt sich
die Hamming-Distanz (Hamming Distance) durch:
d(x, y) = |{1 ≤ i ≤ m|x[i] 6= y[i]}|
• Offensichtlich gilt stets dlev(x, y) ≤ lev(x, y) ≤ edit(x, y).
• Die Damerau-Levenstein-Metrik wurde speziell zur Tippfehlerkorrektur entworfen.
Bemerkungen:
• Die Hamming-Distanz ist die Anzahl der Positionen, an denen sich x
und y unterscheiden. Sie ist nur für Strings gleicher Länge definiert.
• Wird in Problem 3.2 für d eine der Metriken aus Definition 3.2 verwendet, dann spricht man auch von “string matching with k differences”
bzw. von “string matching with k errors”.
• Wird in Problem 3.2 für d die Hamming-Distanz verwendet, so spricht
man auch von “string matching with k mismatches”.
Beispiel 3.2. Die Hamming-Distanz der Strings abcabb und cbacba beträgt 4.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
153
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
155
3. Approximatives String-Matching
String-Metriken
3. Approximatives String-Matching
Berechnung der Stringdistanz
• Da die Metriken edit, lev und dlev sehr ähnlich sind, wird im folgenden nur die Levenstein-Metrik betrachtet.
Beispiel 3.3. Für x = abcabba und y = cbabac gilt:
edit(x, y) = 5
• Algorithmen für die anderen Metriken erhält man durch einfache Modifikationen der folgenden Verfahren.
abcabba −→ bcabba −→ cabba −→ cbba −→ cbaba −→ cbabac
dlev(x, y) = lev(x, y) = 4
• Im folgenden sei m = |x| und n = |y| und es gelte m ≤ n.
abcabba −→ cbcabba −→ cbabba −→ cbaba −→ cbabac
☞ Lösungsansatz: dynamische Programmierung
abcabba −→ bcabba −→ cbabba −→ cbabab −→ cbabac
☞ genauer: berechne die Distanz der Teilstrings x[1 . . . i] und y[1 . . . j]
auf der Basis bereits berechneter Distanzen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
156
Berechnung der Stringdistanz
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
158
Berechnung der Stringdistanz
Die Tabelle LEV sei definiert durch:
Berechnung der Stringdistanz
LEV [i, j] := lev(x[1 . . . i], y[1 . . . j]) mit 0 ≤ i ≤ m, 0 ≤ j ≤ n
Problem 3.3. Gegeben seien zwei Strings x und y. Man ermittle
edit(x, y) bzw. lev(x, y) bzw. dlev(x, y) sowie die zugehörigen Operationen zur Überführung der Strings.
Die Werte für LEV [i, j] können mit Hilfe der folgenden Rekursionsformeln berechnet werden:
Bemerkungen:
• LEV [0, j] = j für 0 ≤ j ≤ n, LEV [i, 0] = i für 0 ≤ i ≤ m
• Wenn x und y Dateien repräsentieren, wobei x[i] bzw. y[j] die i-te
Zeile bzw. j-te Zeile darstellt, dann spricht man auch vom File Difference Problem.
• Unter U NIX steht das Kommando diff zur Lösung des File Difference Problems zur Verfügung.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
157
• LEV [i, j] =
min{ LEV [i − 1, j] + 1,
LEV [i, j − 1] + 1,
LEV [i − 1, j − 1] + δ(x[i], y[j])}
0 falls a = b
• δ(a, b) =
1 sonst
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
159
3. Approximatives String-Matching
Berechnung der Stringdistanz
3. Approximatives String-Matching
Berechnung der Stringdistanz
Beispiel 3.4. Darstellung von LEV als Matrix für x = cbabac und y =
abcabbbaa:
Bemerkungen:
• Die Rekursionsformel spiegelt die drei Operation Löschen, Einfügen
und Substitution wider.
c
b
a
b
a
c
• Die Stringdistanz ergibt sich als LEV [m, n].
• Möchte man nur die Stringdistanz berechnen, so genügt es, sich auf
Stufe i der Rekursion die Werte von LEV der Stufe i − 1 zu merken.
• Benötigt man die zugehörigen Operationen, speichert man LEV
als Matrix und ermittelt die zugehörigen Operationen in einer
“Rückwärtsrechnung”.
0
1
2
3
4
5
6
a
1
1
2
2
3
4
5
b
2
2
1
2
2
3
4
c
3
2
2
2
3
3
3
a
4
3
3
2
3
3
4
b
5
4
3
3
2
3
4
b
6
5
4
4
3
3
4
b
7
6
5
5
4
4
4
a
8
7
6
5
5
4
5
a
9
8
7
6
6
5
5
Die zugehörigen Umwandlungen lauten:
cbabac −→ ababac −→ abcabac −→ abcabbac −→ abcabbbac −→
abcabbbaa
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
160
Berechnung der Stringdistanz
Algorithmus 3.2. [Berechnung der Stringdistanz]
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
162
3. Approximatives String-Matching
Berechnung der Stringdistanz
Veranschaulichung: Die Berechnung der Stringdistanz kann als Pfad
in einem Graphen veranschaulicht werden.
for i := 0 to m do LEV [i, 0] := i end
for j := 1 to n do LEV [0, j] := j end
for i := 1 to m do
for j := 1 to n do
LEV [i, j] := min{ LEV [i − 1, j] + 1, LEV [i, j − 1] + 1,
LEV [i − 1, j − 1] + δ(x[i], y[j])}
end
end
return LEV [m, n]
a
c
b
c
a
b
b
b
a
a
=
Löschoperation
Einfügeoperation
b
a
b
=
Substitution
=
a
=
=
keine Änderung
c
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
161
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
163
3. Approximatives String-Matching
Berechnung der Stringdistanz
Der dargestellte Pfad entspricht der folgenden (nicht optimalen) Umwandlung:
cbabac −→ acbabac −→ abcbabac −→ abcabac −→ abcabbac −→
abcabbbac −→ abcabbbaa
Aus der Rekursionsformel und den Bemerkungen folgt:
Satz 3.5. Die Stringdistanz (für edit, lev und dlev) kann in Zeit O(mn)
und Platz O(m) berechnet werden. Problem 3.3 kann mit Platz O(mn)
gelöst werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
3. Approximatives String-Matching
164
Berechnung der Stringdistanz
Mit einer kleinen Änderung kann die angegebene Rekursionsformel
auch zur Lösung von Problem 3.2 eingesetzt werden.
Es sei M LEV definiert durch:
M LEV [i, j] := min {lev(pat[1 . . . i], text[l . . . j])}
1≤l≤j
d.h., M LEV [i, j] ist die kleinste Distanz zwischen pat[1 . . . i] und einem
Suffix von text[1, j].
Es gilt nun: M LEV [0, j] = 0 für 0 ≤ j ≤ n,
denn pat[1 . . . 0] = und ist stets in text[1 . . . j] ohne Fehler enthalten.
3. Approximatives String-Matching
Berechnung der Stringdistanz
Ansonsten berechnet sich M LEV [i, j] wie LEV [i, j], d.h.:
• M LEV [i, 0] = i für 0 ≤ i ≤ m
• M LEV [i, j] =
min{ M LEV [i − 1, j] + 1,
M LEV [i, j − 1] + 1,
M LEV [i − 1, j − 1] + δ(x[i], y[j])}
Gilt nun M LEV [m, j] ≤ k, so endet in Position j ein Substring y von
text mit lev(pat, y) ≤ k (wobei m die Patternlänge ist).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
166
3. Approximatives String-Matching
Berechnung der Stringdistanz
Beispiel 3.5. Die Tabelle M LEV für pat = ABCDE und text =
ACEABP CQDEABCR.
i
0
1
2
3
4
5
j
0
A
B
C
D
E
0
1
2
3
4
5
1
A
0
0
1
2
3
4
2
C
0
1
1
1
2
3
3
E
0
1
2
2
2
2
4
A
0
0
1
2
3
3
5
B
0
1
0
1
2
3
6
P
0
1
1
1
2
3
7
C
0
1
2
1
2
3
8
Q
0
1
2
2
2
3
9
D
0
1
2
3
2
3
10
E
0
1
2
3
3
2
11
A
0
0
1
2
3
3
12
B
0
1
0
1
2
3
13
C
0
1
1
0
1
2
Für k = 2 ergeben sich die Positionen 3, 10, 13 und 14. Die zugehörigen
Substrings von text sind ACE, ABPCQDE, ABC und ABCR.
Satz 3.6. Problem 3.2 kann für die Metriken edit, lev und dlev in Zeit
O(mn) gelöst werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
165
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
167
14
R
0
1
2
1
1
2
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
4 Lexikalische Analyse und Parsing
Lexikalische Analyse
Aufgaben bei der Compilierung
• Lexikalische Analyse und Parsing sind die wichtigsten Bereiche des
Compilerbaus.
• Prinzipien und Techniken des Compilerbaus beschränken sich nicht
auf die Erstellung von Übersetzern für Programmiersprachen.
• Compilerbau-Techniken finden generell dort Anwendung, wo Zeichenfolgen sequentiell verarbeitet werden, um hieraus abgeleitete
Informationen oder Aktionen zu erzeugen.
• In diesem Kapitel werden wir insbesondere allgemein verwendbare
Compilerbau-Techniken kennenlernen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
4. Lexikalische Analyse und Parsing
168
Lexikalische Analyse
Beispiele f ür die Anwendung von Compilerbau-Techniken:
1. Lexikalische Analyse (Scanning)
• Der Strom von Zeichen, aus denen ein Text besteht, wird sequentiell gelesen und in Symbole (Tokens) separiert.
• Ein Symbol stellt eine Zeichenfolge dar, die eine bestimmte Bedeutung hat.
• Beispiel: Die lexikalische Analyse teilt die Zeile
summe = gebuehr + rate * 12;
wie folgt auf:
Bezeichner: summe, Operator: =, Bezeichner: gebuehr,
Operator: +, Bezeichner: rate, Operator: *,
Ganzzahl-Literal: 12, Trenner: ;
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
170
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
2. Syntaxanalyse (Parsing)
Zuweisung
• Pretty-Printer (Programmtext −→ formatierter Programmtext)
• Anfrage-Interpreter, Shells (Befehle −→ Aktionen)
• Dokumentationswerkzeuge (javadoc, kdoc) (Programmtext −→
HTML-Seiten)
• Indexierer für Web-Seiten (HTML-Seiten −→ Datenbankeinträge)
• XML-Prozessoren (XML-Dokumente −→ Aktionen für die Verarbeitung)
• Symbole des Textes werden Bezeichner
zu grammatikalischen Einheiten zusammengefaßt.
summe
=
Ausdruck
Ausdruck
+
Bezeichner
Ausdruck
• Diese Zusammenfassung wird
durch Syntaxregeln bestimmt.
• Dies kann durch einen Syntaxbaum veranschaulicht werden.
gebuehr
Bezeichner
rate
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
169
Ausdruck
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
*
Ausdruck
Integer
12
171
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Warum teilt man lexikalische Analyse und syntaktische Analyse auf?
3. Semantische Analyse
• Der Text wird auf semantische Fehler hin untersucht. Beispiele:
– Verwendung von Bezeichnern
– Typüberprüfungen
• Bestimmung von Typ-Informationen, um die anschließende Phase
der Synthese vorzubereiten.
• Erzeugung einer Zwischendarstellung
• Vereinfachung des Entwurfs
Eine Grammatik, die direkt auf den Eingabezeichen basiert, wäre typischerweise mit vielen Konflikten behaftet.
Die Trennung führt auch zu einem klareren Sprachentwurf.
• Verbesserung der Effizienz des Compilers
4. Synthese
Ist der Scanner getrennt von den anderen Teilen der Compilierung,
kann er spezifischer und effizienter implementiert werden.
• Auswertung der Zwischendarstellung
• Optimierung
• Transformation der Zwischendarstellung in die Enddarstellung
• Die Portabilität von Compilern wird verbessert.
Besonderheiten des Eingabealphabets und andere spezifische Eigenarten können auf den Scanner beschränkt werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
172
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Lexikalische Analyse
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
174
Lexikalische Analyse
Grundproblem: Wie fassen wir einzelne Zeichen zu Eingabesymbolen
zusammen?
• Die lexikalische Analyse bildet die erste Phase der Compilierung.
• Ihre Hauptaufgabe besteht darin, Eingabezeichen zu lesen und als
Ausgabe eine Folge von Symbolen zu erzeugen, die der Parser syntaktisch analysiert.
Symbol
Zwischendarstellung
Text
Scanner
• Man könnte einen Automaten für ein bestimmtes Erkennungsproblem entwerfen.
Parser
• Solch einen Automaten kann man leicht in ein entsprechendes Programm überführen.
gib naechstes
Symbol
☞ Allgemeines Problem: Spezifikation und Entwurf von Programmen,
deren Aktionen durch bestimmte Textmuster ausgelöst werden.
Symbol−
tabelle
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
• Lexikalische Analyse ist ein klassischer Anwendungsbereich für die
Automatentheorie.
173
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
175
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
4. Lexikalische Analyse und Parsing
Beispiel 4.1. Ein Automat zur Erkennung und Ausgabe von Kommentaren im Stil von C:
6= /
6= *
Reguläre Ausdrücke
Zur Spezifikation von Mustern verwenden wir reguläre Ausdrücke mit
den üblichen Operationen Konkatenation, Auswahl (|) und Wiederholung (*).
/
Wir vereinbaren die folgenden Prioritäten:
*
/
[gespeicherte Zeichen ausgeben]
Lexikalische Analyse
1. Die Wiederholung * hat die höchste Priorität.
*
6= * [Zeichen speichern]
2. Die Konkatenation hat die zweithöchste Priorität.
6 /
=
[* und Zeichen speichern]
3. Die Auswahl hat die niedrigste Priorität
Alle Operationen sind links-assoziativ.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
176
Lexikalische Analyse
• Mit dem Automat geben wir an, wie ein Muster erkannt werden soll.
• Einfacher wäre es, wenn wir nur angeben müssten, was wir erkennen
wollen.
• Wir bräuchten also eine geeignete Spezifikationssprache für zu erkennende Muster.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
• Diese Namen können dann in folgenden regulären Ausdrücken wie
Symbole verwendet werden.
Definition 4.1. Es sei Σ ein Alphabet. Eine reguläre Definition ist eine
Folge von Definitionen der Form
d1 → r 1
d2 → r 2
..
dn → r n
• Zu regulären Ausdrücken können die entsprechenden Automaten zur
Erkennung automatisch konstruiert werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Lexikalische Analyse
• Zur Vereinfachung der Schreibweise ist es vorteilhaft, regulären Ausdrücken Namen zu geben.
• Hierfür eignen sich als Grundkonstrukt reguläre Ausdrücke.
• Diese Automaten müssen dann geeignet simuliert werden.
178
Dabei ist di ein eindeutiger Name und ri ein regulärer Ausdruck über
den Symbolen aus Σ ∪ {d1, . . . , di−1}.
177
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
179
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
4. Lexikalische Analyse und Parsing
lex
Beispiel 4.2. Eine reguläre Definition für Bezeichner im Stil von C:
letter
digit
identifier
→
→
→
| A | B | ··· | Z | a | ··· | z
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
letter ( letter | digit )*
Definition 4.2. Es sei Σ ein Alphabet und r ein regulärer Ausdruck
über Σ.
1. r+ bezeichne den regulären Ausdruck rr∗.
Das Unix-Programm lex ist ein Werkzeug für die lexikalische Analyse:
• lex akzeptiert eine Menge von Mustern, die erweiterte reguläre Ausdrücke und Definitionen darstellen.
• Hieraus produziert lex ein durch Tabellen gesteuertes C-Programm,
das in der Lage ist, Folgen von Zeichen zu erkennen, die auf die
Muster passen.
2. r? bezeichne den regulären Ausdruck |r.
3. Wir führen eine Notation für Zeichenklassen ein:
Für c1, . . . , cn ∈ Σ bezeichne [c1 . . . cn] den regulären Ausdruck
c1| · · · |cn.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
180
Lexikalische Analyse
Für c1 ≤ cn bezeichne [c1 − cn] den regulären Ausdruck c1| · · · |cn.
• Zusätzlich können Aktionen angegeben werden, die bei Erkennung
eines Musters ausgeführt werden sollen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
182
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Benutzung von lex:
Diese beiden Arten der Bezeichnung dürfen innerhalb von [. . .] kombiniert werden.
regulaere Definition
lex−Programm
lex.yy.c
lex.l
Beispiel 4.3. Mit den engeführten Bezeichnungen können Bezeichner
im Stil von C durch folgenden regulären Ausdruck beschrieben werden:
lex.yy.c
[ A-Za-z][ A-Za-z0-9]∗
Text
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
181
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
C−Compiler
a.out
a.out
Folge von Symbolen
183
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
4. Lexikalische Analyse und Parsing
lex-Programme
Definition von regulären Ausdr ücken mit lex:
• Ziffern Buchstaben und manche Sonderzeichen repräsentieren sich
selbst.
Ein lex-Programm besteht aus drei Teilen:
• Es stehen die üblichen Operationen zur Definition von regulären Ausdrücken zur Verfügung.
Deklarationen
%%
Übersetzungsregeln
%%
Hilfsprozeduren
• Die Operatoren +, ? und [ ] stehen gemäß Definition 4.2 zur
Verfügung.
Deklarationsteil:
• Ein Punkt steht für ein beliebiges Zeichen, mit Ausnahme des Zeilentrenners.
• ˆ am Anfang eines Musters repräsentiert den Anfang einer Eingabezeile.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
184
Lexikalische Analyse
• Es gibt eine Negation für Zeichenklassen: [ˆs] bezeichnet alle Zeichen, die nicht zu der durch s spezifizierten Zeichenklasse gehören.
• $ am Ende eines Musters repräsentiert das Ende einer Eingabezeile.
• \ zitiert ein einzelnes, unmittelbar folgendes Sonderzeichen.
Backspace (\b), Zeilentrenner (\n) und Tabulatorzeichen (\t) werden wie in C bzw. Java repräsentiert.
• Einen String bestehend aus beliebigen Zeichen kann man in DoppelAnführungszeichen angeben. Dann haben Sonderzeichen keine spezielle Bedeutung.
• Der Deklarationsteil ist optional. Er enthält Optionen, Deklarationen
von Variablen, symbolischen Konstanten und regulären Definitionen.
• Text der zwischen den speziellen Klammern %{ und %} wird unverändert in die Ausgabe von lex übernommen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
186
Lexikalische Analyse
Hilfsprozeduren:
• Die Hilfsprozeduren sind ebenfalls optional. Dort kann CProgrammtext stehen, der unverändert in die Ausgabe von lex übernommen wird.
• Üblicherweise stehen dort lokale Funktionen, die im zweiten Teil verwendet werden.
Übersetzungsregeln:
• Hier hat man eine Tabelle von Muster und Aktionen.
• Für die Verwendung von regulären Definitionen benutzt man { }.
• Jedes Muster ist ein regulärer Ausdruck.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
185
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
187
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
• Jede Aktion ist eine einzelne C-Anweisung oder ein Folge von CAnweisungen eingeschlossen in { }.
Innerhalb der Aktionen stehen die folgenden wichtigen Variabeln zur
Verfügung:
• Statt einer C-Anweisung kann auch | angegeben werden. In diesem
Fall wird für das Muster die gleiche Aktion wie für das folgende Muster ausgeführt.
• extern char yytext[];
• Alle Zeichen, die nicht in auf eines der Muster passen, werden in die
Ausgabe kopiert.
• extern int yyleng;
Aus der Tabelle konstruiert lex eine Funktion yylex(), die in der Datei
lex.yy.c abgelegt wird.
• extern int yylineno;
Die Zeichenfolge, die auf das erkannte Muster paßt.
Länge von yytext.
Nummer der aktuellen Eingabezeile.
Übersetzt man diese C-Datei und bindet die lex-Bibliothek hinzu, hat
man einen funktionierenden Scanner.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
188
Lexikalische Analyse
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
190
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Beispiel 4.4. Entfernen aller Großbuchstaben:
Beispiel 4.5. Numerierung von Zeilen:
%%
[A-Z]+
%%
%%
ˆ.*\n
%%
;
Beispiel 4.6. Ausgabe aller Bezeichner mit Zeilennummer:
Mit
$ lex removeuc.l
$ cc lex.yy.c -lfl
erhält man ein Programm, daß von der Standardeingabe liest und dabei
alle Großbuchstaben entfernt.
Die Option -lfl unter Linux sorgt dafür, daß die flex-Bibliothek eingebunden wird.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
printf( "%4d\t%s", yylineno-1, yytext );
189
letter
[_A-Za-z]
digit
[0-9]
letterOrDigit
[_A-Za-z0-9]
whitespace
[ \t\n]
other
.
%%
{letter}{letterOrDigit}*
{whitespace}
{other}
%%
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
printf( "%d: %s\n", yylineno, yytext );
;
;
191
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Mehrdeutigkeiten:
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Beispiel 4.7. Zeichen, Wörter und Zeilen einer Datei zählen:
• An dem letzten Beispiel sieht man, daß die angegebenen Muster
mehrdeutig sein können.
• lex verwendet zwei Regeln, um solche Mehrdeutigkeiten aufzulösen:
– lex benutzt immer das Muster, das die längstmögliche Folge von
Eingabezeichen repräsentiert.
– Repräsentieren dabei immer noch zwei Muster die gleiche Eingabe, so wird das erste Muster innerhalb der Übersetzungsregeln
verwendet.
%{
int nchar, nword, nline;
%}
%%
\n
{ ++nchar; ++nline; }
[ˆ \t\n]+
{ ++nword; nchar += yyleng; }
.
{ ++nchar; }
%%
int main()
{
yylex();
printf( "%d %d %d\n", nchar, nword, nline );
}
• Diese Regeln setzt man gezielt ein. Man gibt die spezifischeren Muster, die eine Teilmenge eines allgemeineren Musters beschreiben,
zuerst an.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
192
Lexikalische Analyse
• Beispiel:
%%
"int"
[_a-zA-Z][_a-zA-Z0-9]+
%%
4. Lexikalische Analyse und Parsing
194
Lexikalische Analyse
Beispiel 4.8. Lexikalische Analyse für einen Tischrechner:
printf( "Schluesselwort" );
printf( "Bezeichner" );
Durch die von lex angewendeten Regeln ist sichergestellt, daß int
als Schlüsselwort erkannt wird und nicht als Bezeichner.
Das nächste Beispiel verdeutlicht den Gebrauch von %{ %} im Deklarationsteil und die Verwendung von Hilfsprozeduren.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
193
%{
extern double atof();
%}
digits
([0-9]+)
point
"."
sign
[+-]?
exponent
([eE]{sign}{digits})
%%
{digits}({pt}{digits}?)?{exponent}?
|
{digits}?{pt}{digits}{exponent}?
{
printf( "%lf\n", atof( yytext ) ); }
[ \t]+
;
\n
|
.
;
%%
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
195
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Erkennung von Schlüsselwörtern
• Die reservierten Worte einer Programmiersprache könnte man leicht
als einzelne Muster definieren.
4. Lexikalische Analyse und Parsing
static void classifyIdentifier()
{
char ** low;
char ** high;
char ** mid;
int
rc;
low = rwlist;
high = rwlist + sizeof( rwlist ) / sizeof( rwlist[0] ) - 1;
while ( low <= high )
{
mid = low + (high-low) / 2;
if ( (rc=strcmp( *mid, yytext )) == 0 )
{
printf( "%s ist Schluesselwort\n", yytext );
return;
}
• Leider vergrößert eine lange Liste solcher Muster, die sich selbst darstellen, das von lex generierte Programm deutlich.
• Es ist effizienter, für reservierte Worte und Bezeichner nur ein einzelnes Muster zur Verfügung zu stellen.
• In einer nachgelagerten Funktion untersucht man dann einen Bezeichner daraufhin, ob er ein reserviertes Wort darstellt.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
196
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
%{
static void classifyIdentifier();
%}
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
198
Lexikalische Analyse
else
if ( rc < 0 )
low = mid + 1;
else
high = mid - 1;
Beispiel 4.9. Erkennung von Bezeichnern und Schlüsselwörtern:
letter
letterOrDigit
%%
{letter}{letterOrDigit}*
%%
static char *rwlist[] =
{
"break",
"continue",
...
"while"
};
Lexikalische Analyse
}
printf( "%s ist Bezeichner\n", yytext );
[_a-zA-Z]
[_a-zA-Z0-9]
}
classifyIdentifier();
197
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
199
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Generierung eines Scanners
4. Lexikalische Analyse und Parsing
1.
q00
Lexikalische Analyse
0
:= eps({q0}); Q :=
{q00 }; δ
:= ∅;
2. Falls alle Zustände in Q0 markiert sind: STOP. Andernfalls gehe zu 3.
• Grundlage der Generierung eines Scanners ist die Konstruktion eines endlichen Automaten zu einem regulären Ausdruck (siehe Kapitel 3).
• Zunächst werden die NEAs zu den regulären Ausdrücken bzw. zu
den regulären Definitionen erzeugt.
3. Sei S ein nichtmarkierter Zustand aus Q0.
Markiere S.
Für alle a ∈ Σ:
• Die einzelnen NEAs werden zu einem Automaten zusammengefügt.
• Sei T := eps({p|(q, a, p) ∈ ∆, q ∈ S})
• Falls T 6∈ Q0 dann nehme T in Q0 auf.
• Erweitere δ um (S, a, T ).
• Dieser NEA wird in einen DEA (ohne -Übergänge) transformiert.
Gehe zu 2.
• Der so entstandene DEA wird minimiert.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
200
Lexikalische Analyse
Umwandlung eines NEA in einen DEA
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
202
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Beispiel 4.10. NEA zum regulären Ausdruck a(a|b)∗:
a
0
a
1
ε
2
0
Sei M = (Q, Σ, ∆, q0, F ) ein NEA. Der zu M gehörende DEA M =
(Q0, Σ, δ, q00 , F 0) ist gegeben durch:
Q0 = P(Q)
q00
0
F
b
3
ε
4
ε
ε
q00 = 00 = {0}; Q0 = {00}
= eps({q0})
= {S ⊆ Q|S ∩ F 6= ∅}
δ(S, a) = eps({p|(q, a, p) ∈ ∆, q ∈ S}) für a ∈ Σ
ausgw. Zustand
00
10
20
30
neue Zustände
10 = {1, 2, 4}, 30 = ∅
20 = {2, 3, 4}
Bemerkung: Tätsächlich tritt i.d.R. nur eine kleine Teilmenge von P(Q)
als Zustand im DEA auf.
schrittweise Konstruktion: Tafel ✎.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
201
neues Q0
{00, 10, 30}
{00, 10, 20, 30}
{00, 10, 20, 30}
{00, 10, 20, 30}
∪δ
{(00, a, 10), (00, b, 30)}
{(10, a, 20), (10, b, 20)}
{(20, a, 20), (20, b, 20)}
{(30, a, 30), (30, b, 30)}
203
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Zugehöriger DEA:
Lexikalische Analyse
der Zeichen als Index angelegt, dessen Inhalt die Zeichenklassen
sind.
a, b
{1,2,4}
4. Lexikalische Analyse und Parsing
a
1’
• Ein Problem tritt auf, wenn zwei Klassen A und B nicht disjunkt sind.
Dann ersetzt ein Scanner-Generator diese durch drei Klassen A \ B,
B \ A und A ∩ B.
2’
a
b
{2,3,4}
0’
{0}
In den Automaten gibt es dann überall dort, wo es einen Übergang
unter A bzw. B gäbe, jeweils zwei Übergänge unter A \ B und A ∩ B
bzw. B \ A und A ∩ B.
b
{}
3’
a, b
Der Zustand 30 ist der Fehlerzustand. Er ist der Nachfolgezustand eines
Zustands q unter a, wenn es keinen Übergang unter a aus q heraus gibt.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
204
Lexikalische Analyse
Zeichenklassen:
• Diese Aufteilung findet solange statt, bis jedes Zeichen zu genau einer Zeichenklasse gehört.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
Gegeben sei eine Folge von regulären Definitionen:
• Zeichenklassen werden genutzt, um die entstehenden Automaten zu
verkleinern.
letter
digit
206
d1 → r 1
..
dn → r n
[a-z]
[0-9]
Sei Mi = (Qi, Σ, ∆i, q0,i, Fi) der NEA zu di.
Man erhält den NEA für die gesamte Folge der regulären Definitionen,
indem man:
Statt 36 Übergängen benötigt man so nur zwei Übergänge.
• Sämtliche Symbole werden auf diese Weise (implizit) einer Zeichenklassen zugeordnet. Für Zeichen, die nicht explizit in einer Klasse
vorkommen, wird implizit eine eigene Klasse definiert.
• einen neuen Startzustand q0 generiert und
• -Übergänge von q0 zu jedem q0,i legt.
• Für die effiziente Implementierung wird ein Feld mit dem ASCII-Code
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
205
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
207
4. Lexikalische Analyse und Parsing
Lexikalische Analyse
4. Lexikalische Analyse und Parsing
Konstruktion eines Parsers
• Für yacc wird die Grammatik gemäß BNF angegeben. Eine Grammatik besteht aus einer Folge von Regeln.
Veranschaulichung:
q0,1
• Eine Regel besteht aus einer linken Seite und einer rechten Seite,
die durch einen Doppelpunkt gestrennt sind.
ε
q0
ε
• Die linke Seite besteht aus einem eindeutigen Grammatikbegriff
(non-terminal Symbol)
q0,2
ε
• Die rechte Seite besteht aus einer Folge von Formulierungen, die
durch | voneinander getrennt sind.
q0,3
• Da Grammatikbegriffe und (Terminal-)Symbole gleich aussehen,
muß man die Symbole vor der eigentlichen Grammatik vereinbaren.
• %% trennt diese beiden Teile.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
208
Konstruktion eines Parsers
Konstruktion eines Parsers mit yacc
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
210
Konstruktion eines Parsers
Beispiel 4.11. Erstes Beispiel einer yacc-Grammatik:
%token NUMBER
• Ein Compiler muß entscheiden, ob eine Folge von Eingabesymbolen ein Satz in einer Sprache ist. Eine Grammatik beschreibt eine
Sprache.
• Können wir eine Grammatik direkt für die Erkennung einer Sprache
verwenden?
• Prinzipiell sollte dies möglich sein. Kontextfreie Sprachen können mit
Kellerautomaten erkannt werden.
• Das Programm yacc ermöglicht es uns, einen Parser für eine Sprache auf der Basis ihrer Grammatik zu generieren.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
209
%%
expression
: expression ’+’ NUMBER
| NUMBER
Liegt dieser Text in der Datei first.y so wird mit dem Befehl
$ yacc first.y
eine Datei y.tab.c erzeugt, die die wesentlichen Teile des Parsers
enthält.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
211
4. Lexikalische Analyse und Parsing
Konstruktion eines Parsers
• yacc prüft die definierte Grammatik und konstruiert einen Parser zur
Erkennung der Sprache.
• Der Parser ist ein Kellerautomat, der besteht aus:
– einem großen Stack, auf dem die aktuellen Zustände abgelegt
werden,
– einer Übergangsmatrix, mit der für jede mögliche Kombination von
aktuellem Zustand und nächstem Eingabesymbol ein neuer Zustand bestimmt wird,
– einer Tabelle von Aktionen, die vom Benutzer definiert sind und in
bestimmten Situationen der Erkennung ausgeführt werden und
– einem Interpreter, der für die Ausführung des Kellerautomaten
sorgt.
• Das ganze ist verpackt als Funktion yyparse(), die sich der Funktion yylex() zur lexikalischen Analyse bedient.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
212
Konstruktion eines Parsers
4. Lexikalische Analyse und Parsing
Konstruktion eines Parsers
Beispiel 4.12. lex-Programm first.l zu first.y:
%{
#include "y.tab.h"
%}
whitespace
other
%%
[0-9]+
{whitespace}+
{other}
%%
[ \t\n]
.
return( NUMBER );
;
return( yytext[0] );
Weiterhin brauchen wir noch eine main()-Funktion, die yyparse()
aufruft.
int main() { yyparse(); }
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
214
Konstruktion eines Parsers
Als letztes wird noch eine Funktion yyerror benötigt. Diese Funktion
ruft der Parser auf, wenn er einen Syntaxfehler erkennt.
Putting it all Together
#include <stdio.h>
Die Repräsentation von Symbolen muß zwischen yylex() und
yyparse() abgestimmt werden.
yacc hilft hierbei. Das Kommando
yyerror( char * errmsg )
{
fprintf( stderr, "%s\n", errmsg );
}
$ yacc -d first.y
Diese Funktionen seien in einer Datei first.c. Die Befehle
sorgt dafür, daß eine Datei y.tab.h mit C-Präprozessor-Anweisungen
erzeugt wird.
$ lex first.l
$ yacc -d first.y
$ cc first.c lex.yy.c y.tab.c -lfl
Diese Datei sollte in lex importiert werden (#include-Anweisung).
erzeugen dann in a.out einen Parser.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
213
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
215
4. Lexikalische Analyse und Parsing
Konstruktion eines Parsers
4. Lexikalische Analyse und Parsing
Konstruktion eines Parsers
– Der Wert des an i-ter Stelle stehenden Grammatikbegriff einer Formulierung wird mit $i bezeichnet.
– Die Übergabe eines Wertes von lex nach yacc geschieht durch
Zuweisung an die Variable yylval.
$ a.out
4711 + 0815
ˆD
$
Da die Eingabe korrekt in bezug auf die definierte Grammatik ist, wird
keine Ausgabe erzeugt. Andernfalls gibt es eine kurze Fehlermeldung:
syntax error.
Beispiel 4.13. Konstruktion eines simplen Addierers:
%token NUMBER
%%
calculation
: expression
{ printf( "%d\n", $1 ); }
expression
: expression ’+’ NUMBER
{ $$ = $1 + $3; }
| NUMBER
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
216
Konstruktion eines Parsers
4. Lexikalische Analyse und Parsing
218
Konstruktion eines Parsers
Das zugehörige lex-Programm:
Ausführen von Aktionen
• Mit den bisherigen Techniken kann nur überprüft werden, ob ein Text
syntaktisch korrekt aufgebaut ist.
• Möchte man den Text verarbeiten, ist es notwendig, mit den Grammatikbegriffen Aktionen zu verbinden.
• Hierzu bietet yacc die folgenden Möglichkeiten:
– Zu jeder Formulierung kann ein Block von C-Anweisungen angegeben werden.
– Mit jedem Grammatikbegriff ist ein Wert verbunden.
– Der Wert, der mit dem Grammatikbegriff der linken Regelseite verbunden ist, trägt die Bezeichnung $$.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
217
%{
#include "y.tab.h"
extern int yylval
%}
whitespace
[ \t\n]
other
.
%%
[0-9]+
{ yylval = atoi( yytext ); return( NUMBER ); }
{whitespace}+
;
{other}
return( yytext[0] );
Aufruf:
$ a.out
4711 + 0815
ˆD
5526
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
219
4. Lexikalische Analyse und Parsing
Konstruktion eines Parsers
pt
"."
sign
[+-]?
exponent
([eE]{sign}{digits})
%%
{digits}({pt}{digits}?)?{exponent}?
{digits}?{pt}{digits}{exponent}?
Beispiel 4.14. Definitionen für einen Tischrechner:
%{
#define YYSTYPE double
%}
%token NUMBER
%left ’+’ ’-’
%left ’*’ ’/’
%%
line
: /* leer */
| line expression ’\n’
{ printf( "%lf\n", $2 ); }
[ \t]+
\n
.
%%
4. Lexikalische Analyse und Parsing
Konstruktion eines Parsers
|
{ yylval = atof( yytext );
return( NUMBER ); }
;
|
return yytext[0];
Bemerkungen:
• Mittels left bzw. right wird die Assoziativität von Operatoren vereinbart.
expression
: expression ’+’ expression
{ $$ = $1 + $3; }
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
• Darüberhinaus auch die Priorität. Die Operatoren haben gemäß der
220
Konstruktion eines Parsers
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
4. Lexikalische Analyse und Parsing
222
Konstruktion eines Parsers
Reihenfolge aufsteigende Priorität.
| expression ’-’ expression
{ $$ = $1 - $3; }
| expression ’*’ expression
{ $$ = $1 * $3; }
| expression ’/’ expression
{ $$ = $1 / $3; }
| ’(’ expression ’)’
{ $$ = $2; }
| NUMBER
• yylval und der Wert-Stack werden im Parser mit dem Typ YYSTYPE
vereinbart. Hier ist int voreingestellt. Mittels der angegebenen Definition kann dies umgesetzt werden.
lex-Programm:
%{
#include "y.tab.h"
extern double atof();
extern double yylval;
%}
digits
([0-9]+)
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
221
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
223
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
5 XML und Analyse von XML-Dokumenten
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
Was ist XML?
• XML ist eine Sprache zur Repräsentation von Dokumenten.
Erläuterungen zu XML vom W3C:
• Die Extensible Markup Language (XML) ist ein einfaches und sehr
flexibles, von SGML abgeleitetes Textformat.
• SGML := Standard Generalized Markup Language
• XML wurde entworfen, um die hohen Anforderungen an das elektronische Publizieren abzudecken und
• wird darüberhinaus eine wichtige Rolle für den Austausch unterschiedlichster Daten über das Web spielen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
224
Einf ¨uhrung in XML
• Durch XML wird gemäß SGML die Auszeichnung von Dokumenten
(markup) formalisiert und von System- und Verarbeitungsabhängigkeiten gelöst.
• Durch XML wird eine Syntax bereitgestellt, mit der die Struktur von
Dokumenten eines Typs unabhängig von der weiteren Verwendung
und Darstellung beschrieben werden kann.
• Oft wird XML als Metasprache bezeichnet, da über XML Auszeichnungssprachen definiert werden können (erweiterbare Auszeichnungssprache).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
226
Einf ¨uhrung in XML
Auszeichnungssprache
Was soll durch XML ermöglicht werden? Gemäß W3C:
• Medienunabhängiges elektronisches Publizieren von Informationen
in mehreren Sprachen
• Bei einer Auszeichnungssprache werden die Inhalte eines Datenstroms durch Auszeichnungen (tags) strukturiert.
• Definition von plattformunabhängigen Protokollen zum Datenaustausch (speziell für den elektronischen Handel)
• Ausschließlich die Auszeichnungen dienen zur Strukturierung des Inhalts.
• Automatische Verarbeitung übertragener Daten durch Software
• Die Auszeichnungen sind so gehalten, daß sie selbst als reiner Text
innerhalb des Inhalts eines Dokuments zu identifizieren sind.
• Datenverarbeitung mit preisgünstiger Software
• Benutzerdefinierte Präsentation von Informationen
• Durch solche Auszeichnungen werden Teile des Inhalts benannt.
Diese Inhalte heißen Elemente.
• Auffinden von Informationen durch Metadaten (Informationen über
Informationen)
• Die Länge der Auszeichnungen ist variabel und kann mit Informationen über den ausgezeichneten Inhalt angereichert werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
225
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
227
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
Dokument und Dokumenttyp
Ein XML-Dokument ist eine Instanz eines XML-Dokumenttyps, der wiederum durch die Dokumentenrepräsentationssprache XML beschrieben wird.
Einf ¨uhrung in XML
<ProdName>Web-Visitenkarte</ProdName>
<UnitPrice>1.00</UnitPrice>
</Item>
</Items>
</Order>
Order
Dokumenten−
repräsentations−
sprache
XML
SGML
5. XML und Analyse von XML-Dokumenten
OrderHeader
Items
Dokumenttyp
HTML
XHTML
MeinTyp
OrderID
Item
OrderDate
Customer
HTML−
Dokument
XHTML−
Dokument
MeinTyp
Dokument
Dokumentinstanz
CustName
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
228
Einf ¨uhrung in XML
Beispiel 5.1. Ein XML-Dokument zur Repräsentation einer Bestellung als erstes
CustEmailAdress
ProdName
UnitPrice
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
230
Einf ¨uhrung in XML
Wohlgeformtheit
einfaches Beispiel:
<?xml version="1.0"?>
<!DOCTYPE Order SYSTEM "http://some-provider.de/order.dtd">
<Order>
<OrderHeader>
<OrderID>4711</OrderID>
<OrderDate>2000-11-11</OrderDate>
<Customer>
<CustName>Dr. Peter Becker</CustName>
<CustEmailAdress>
[email protected]
</CustEmailAdress>
</Customer>
</OrderHeader>
<Items>
<Item quantity="1" deliveryDate="2001-01-02">
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Ein XML-Dokument ist wohlgeformt, wenn es:
• Die syntaktischen Regeln von XML erfüllt,
• alle Elemente ordnungsgemäß verschachtelt sind und
• alle referenzierten Entities geeignet deklariert sind.
☞ Für wohlgeformte Dokumente kann der Strukturbaum erstellt werden, ohne daß Kenntnisse über den Dokumenttyp erforderlich sind.
229
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
231
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
Dokumenttypen
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
Beispiel 5.2. Eine DTD für das Dokument von Beispiel 5.1:
• Für die Verarbeitung von Daten ist das Vorhandensein einer Schemadefinition elementar.
• Auch wenn ein XML-Dokument wohlgeformt ist, so ist eine sinnvolle
Weiterverarbeitung erst durch die Angabe eines zugehörigen Dokumenttyps möglich.
<!DOCTYPE Order [
<!ELEMENT Order (OrderHeader, Items) >
<!ELEMENT OrderHeader (OrderID, OrderDate, Customer) >
<!ELEMENT Customer (Custname, CustEmailAdress?) >
<!ELEMENT Items (Item+) >
<!ELEMENT Item (ProdName, UnitPrice) >
<!ATTLIST Item quantity
CDATA #REQUIRED
deliveryDate CDATA #IMPLIED >
<!ELEMENT ProdName (#PCDATA) >
. . .
]>
• Es muß im voraus bekannt sein, welche Elemente in einem Dokument vorkommen können, um auf diesen sinnvolle Operationen
ausführen zu können.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
232
Einf ¨uhrung in XML
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
234
Einf ¨uhrung in XML
Dokumenttypdeklaration
• Über die Deklaration eines Elements wird sein Name und sein Inhaltsmodell beschrieben.
• Ein XML-Dokument kann eine Dokumenttypdeklaration (document
type declaration) enthalten.
• Soll das Element keine weiteren Unterelemente haben, so ist das
Inhaltsmodell EMPTY (leer) oder PCDATA (nur Zeichen enthaltend).
• In solch einer Dokumenttypdeklaration werden die zur Verfügung stehenden Auszeichnungen direkt angegeben oder
• Ansonsten wird eine Strukturierung von Unterelementen angegeben. Hierfür stehen die folgenden Strukturierungsmöglichkeiten zur
Verfügung:
• es wird auf eine Auszeichnungsdeklaration verwiesen.
• In der Auszeichnungsdeklaration wird eine Grammatik angegeben,
der das aktuelle Dokument folgen soll.
• Diese Grammatik wird als Dokumenttypdefinition (document type definition, DTD) bezeichnet.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
233
– Sequenz: Unterelemente werden durch Komma getrennt angegeben
– Auswahl: Unterelemente werden durch | getrennt angegeben
– Wiederholung: Ein + hinter einem Unterelement gibt an, daß dieses beliebig oft auftreten kann, jedoch mindestens einmal auftreten muß.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
235
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
– Wiederholung: Ein * hinter einem Unterelement gibt an, daß dies
beliebig oft eventuell auch gar nicht auftreten kann.
– Option: Ein ? hinter einem Unterelement gibt an, daß dieses einmal oder gar nicht auftreten kann.
• PCDATA steht für Parsed Character Data. Dies sind Zeichenfolgen,
die spitze Klammern, Apostroph, Anführungszeichen und & nicht enthalten.
• Diese Zeichen sind Bestandteil der Auszeichnung. Sie müssen über
sogenannte Entity-Referenzen aufgelöst werden. Innerhalb solcher
Zeichenfolgen werden Entity-Referenzen ersetzt.
• CDATA steht für Character Data. Hier ist alles erlaubt, es findet keine
Auflösung der Zeichen statt.
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
In einer DTD können interne und externe Entity-Referenzen deklariert
werden.
Beispiel 5.3.
<!ENTITY vorlesungstitel
"Textalgorithmen: unverstaendlich und praxisfern">
In einem XML-Dokument kann nun eine Referenz wie folgt verwendet
werden:
<titel>&vorlesungstitel;</titel>
Beispiel 5.4. Durch die Deklaration von
<!ENTITY ueberdendozent
SYSTEM "http://www.inf.fh-bonn-rhein-sieg.de/becker.xml">
wird eine Referenz auf ein externes XML-Dokument erzeugt. Verwendet
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
236
Einf ¨uhrung in XML
Entity-Referenzen
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
238
Einf ¨uhrung in XML
• Entity-Referenzen sind Platzhalter für Ersetzungen.
man nun &ueberdendozent;, so wird an dieser Stelle das komplette
XML-Dokument eingesetzt.
• Eine Entity-Referenz kann Zeichendaten beschreiben oder eine komplette XML-Instanz.
• Durch externe Entity-Referenzen werden XML-Dokumente für andere XML-Dokumente wiederverwendbar.
• Ein Entity ist irgendeine Einheit von wohlgeformten XML, auf die eine
Entity-Referenz entweder direkt oder über eine URL verweist.
• Bei der Einfügung findet wiederum eine Ersetzung von EntityReferenzen statt.
• Entity-Referenzen werden in der DTD deklariert.
• Ein XML-Dokument muß also nicht physikalisch aus einer einzelnen
Datei bestehen.
• In PCDATA haben sie die Form: &Name;
• Einige Entity-Referenzen kennt der Parser implizit. Dies sind die
Entity-Referenzen für die Darstellung der in PCDATA nicht erlaubten
Zeichen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
237
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
239
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
5. XML und Analyse von XML-Dokumenten
Einf ¨uhrung in XML
Dokumentzentrierte XML-Dokumente
Gültigkeit
Ein wohlgeformtes XML-Dokument heißt gültig, wenn es:
• inhomogen strukturiert
• die durch die DTD definierten Beschränkungen erfüllt.
• Reihenfolge der Elemente ist oft wichtig
• viel “mixed content”
• Informationen auf allen Ebenen
• Volltextsuche ist unbedingt notwendig
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
240
Einf ¨uhrung in XML
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
242
5. XML und Analyse von XML-Dokumenten
Datenzentrierte XML-Dokumente
Analyse von XML-Dokumenten
SAX
• Repräsentation von sehr stark strukturierten Informationen, Daten im
herkömmlichen Sinn (z.B. in relationalen DB)
• Reihenfolge ist oft irrelevant
• Simple API for XML (SAX) ist ein de-facto Standard für ein ereignisbasiertes Parsen von XML-Dokumenten.
• SAX definiert eine Schnittstelle, die es erlaubt, die Informationen eines XML-Dokumentes in linearer Reihenfolge zu durchlaufen, ohne
eine Baumstruktur aufzubauen.
• sind einheitlich und meist homogen strukturiert
• haben Datentypen
• Es existieren Implementierungen für die meisten gängigen Programmiersprachen (Java, Perl, Python, C++).
• Informationen liegen in den Blättern
• selten “mixed content”
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
241
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
243
5. XML und Analyse von XML-Dokumenten
Analyse von XML-Dokumenten
Bei einer ereignisbasierten API gibt es zwei wichtige Programmkomponenten:
1. Einen Treiber der Ereignisse erzeugt. Hier ist dies der XML-Parser.
2. Handler, die diese Ereignisse verarbeiten. Hier sind dies Klassen, die
bestimmte Schnittstellen implementieren.
• Es muß nicht das gesamte Dokument gelesen werden, bevor es bearbeitet werden kann. Die Baumstruktur des Dokuments wird nicht
aufgebaut.
• Stattdessen werden beim Parsen Ereignisse erzeugt. Diese können
Aktionen auslösen.
5. XML und Analyse von XML-Dokumenten
Analyse von XML-Dokumenten
Die Ereignisse können grob in die folgenden Arten eingeteilt werden:
Ereignismodell von SAX
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
244
Analyse von XML-Dokumenten
Beispiel 5.5. Für das XML-Dokument
• Ereignisse durch den Inhalt eines XML-Dokument
• Ereignisse durch Validierung
• Ereignisse durch Fehler
Um auf Ereignisse reagieren zu können, müssen sogenannte Handler
implementiert werden.
Wird zu einem Ereignis kein passender Handler gefunden, so bleibt dieses Ereignis unbehandelt.
Zu den meisten Ereignissen werden vom Parser Parameter übergeben.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
246
5. XML und Analyse von XML-Dokumenten
Analyse von XML-Dokumenten
<<interface>>
ContentHandler
<?xml version="1.0"?>
<rowset>
<row>SAX Test</row>
</rowset>
<<interface>>
ErrorHandler
<<interface>>
DTDHandler
<<interface>>
EntityHandler
:MyContentHandler
werden die folgenden Ereignisse erzeugt:
4.1:setDocumentLocator()
StartDocument()
StartElement( "rowset" )
StartElement( "row" )
Characters( "SAX Test" )
EndElement( "row" )
EndElement( "rowset" )
EndDocument()
:MyErrorHandler
4.2:startDocument()
:MyDTDHandler
4.3:startElement()
4.4:characters()
:MyEntityHandler
4.5:endElement()
4.n: endDocument()
<<interface>>
2:new()
:XMLReader
main
3:setContentHandler()
1:createXMLReader()
4:parse()
:SAXParser
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
245
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
:XMLReaderFactory
1.1:new()
247
5. XML und Analyse von XML-Dokumenten
Analyse von XML-Dokumenten
Schnittstellen zum Parser:
• Der XML Reader dient dazu, den XML-Parser zu konfigurieren, die
Event Handler zu registrieren sowie das Parsen zu starten.
• Durch die Implementierung des Content Handlers kann auf Ereignisse reagiert werden, die durch den Inhalt eines XML-Dokuments
entstehen.
5. XML und Analyse von XML-Dokumenten
Analyse von XML-Dokumenten
parser.parse( uri );
}
catch ( IOException e ) {
System.out.println(
"Error reading URI: " + e.getMessage() ) ; }
catch ( SAXException e ) {
System.out.println(
"Error parsing URI: " + e.getMessage() ) ; }
}
• Der Error Handler unterscheidet zwei Arten von Fehlern:
– Error: Fehler, die beim Parsen übersprungen werden können
– Fatal Errror: Fehler, die zum Abbruch des Parsens führen.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
248
Analyse von XML-Dokumenten
Beispiel 5.6. Parsing von XML-Dokumenten mit SAX:
5. XML und Analyse von XML-Dokumenten
250
Analyse von XML-Dokumenten
DOM: Bearbeitung von XML-Dokumenten
public void parserDemoSAX( String uri )
{
System.out.println( "Parsing XML File: " + uri + "\n\n" );
• DOM ist ein Standard (W3C), SAX ist public-domain Software.
contentHandler = new MyContentHandler();
errorHandler = new MyErrorHandler();
• DOM zielt ab auf die Bearbeitung eines Dokuments, SAX auf das
Parsing eines XML-Dokuments.
try
{
• DOM Level 1: Generische Navigation und Bearbeitung eines Dokuments
XMLReader parser = XMLReaderFactory.createXMLReader(
PropertiesReader().getInstance()
.getProperty( "parserClass" ) );
• DOM spezifiziert Interfaces für die entsprechenden Funktionalitäten
und verschiedene Sprachen: z.B. Java, Javascript und CORBA.
parser.setContentHandler( contentHandler );
parser.setErrorHandler( errorHandler );
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
249
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
251
5. XML und Analyse von XML-Dokumenten
Analyse von XML-Dokumenten
Navigation mit dem Document Object Model
"Error parsing URI: " + e.getMessage() ) ; }
public void printNode( Node node, String ident )
{
System.out.println( ident + node.getNodeName() );
System.out.println( ident + node.getNodeValue() );
getParentNode()
getPreviousSibling()
OrderHeader
Items
Node child = node.getFirstChild();
while ( child != 0 )
{
printNode( child, ident + "
" );
child = child.getNextSibling();
}
}
getNextSibling()
OrderID
Item
OrderDate
Customer
CustName
CustEmailAdress
ProdName
UnitPrice
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
5. XML und Analyse von XML-Dokumenten
Analyse von XML-Dokumenten
}
Order
getFirstChild()
5. XML und Analyse von XML-Dokumenten
252
Analyse von XML-Dokumenten
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
254
6. Textkompression
Allgemeines zur Textkompression
6 Textkompression
DOM: Beispiel in Java
• Das Ziel der Datenkompression ist es, eine gegebene Information
(Datenquelle) auf eine kompaktere Weise zu repräsentieren.
public void parserDemoDOM( String uri )
{
System.out.println( "Parsing XML File: " + uri + "\n\n" );
• Dies geschieht, indem Strukturen bzw. Regelmäßigkeiten in der Datenquelle erkannt und ausgenutzt werden.
DOMParser parser = new DOMParser();
try
{
• Beispiel: Morse-Alphabet
Häufig vorkommende Buchstaben
haben einen kürzeren MorseCode als weniger häufige.
parser.parse( uri );
Document doc = parser.getDocument();
printNode( doc, "" );
e
j
1
•
•–––
•––––
}
catch ( Exception e ) {
System.out.println(
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
253
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
255
6. Textkompression
Allgemeines zur Textkompression
Vorgehensweise bei der Kompression:
Modell
Datenquelle
Text
Allgemeines zur Textkompression
Modellierungsansatz:
Modell
Komprimierer
6. Textkompression
Dekomprimierer
• Bei statistischen Verfahren wird versucht, eine Wahrscheinlichkeit für
Zeichen oder Zeichenfolgen zu bestimmen. Die Kompression erfolgt,
indem Zeichenfolgen mit einer höheren Wahrscheinlichkeit ein kürzerer Code zugewiesen wird.
Text
Kommunikationskanal
• Komprimierer und Dekomprimierer verfügen über das gleiche Modell.
• Bei wörterbuchbasierten Verfahren versucht man, Zeichenfolgen
durch eine Referenz auf ein Wörterbuch zu ersetzen. Hierzu enthält
das Wörterbuch häufig auftretende Zeichenfolgen.
• Der Komprimierer erzeugt eine Codierung der Datenquelle auf der
Basis des Modells.
• Der Dekomprimierer nutzt das gleiche Modell, um aus der komprimierten Darstellung die Datenquelle zu rekonstruieren.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6. Textkompression
256
Allgemeines zur Textkompression
Eigenschaften von Kompressionsverfahren
6. Textkompression
258
Allgemeines zur Textkompression
Anpassung des Modells bzw. der Codierung an die Datenquelle:
• Bei statischen Verfahren wird stets die gleiche Codierung für die
Kompression benutzt. Es findet keine Anpassung an die Datenquelle
statt (Morse-Alphabet).
Informationsverluste bei der Kompression/Dekompression:
• Verfahren, bei denen die Datenquelle exakt aus der komprimierten
Darstellung rekonstruiert werden kann, heißen verlustfrei.
• Treten dagegen möglicherweise Informationsverluste auf, spricht
man von nicht verlustfreien Verfahren. Solche Verfahren sind z.B. für
Bilder, Videos oder Audioübertragung geeignet.
• Vorteil der nicht verlustfreien Verfahren: höhere Kompressionsraten.
• Für die Textkompression kommen nur verlustfreie Verfahren in Frage.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
257
• Bei semi-adaptiven Verfahren wird die Datenquelle zunächst einer
Häufigkeitsanalyse unterzogen, und die Codierung wird entsprechend angepaßt. Nachteil: Die Datenquelle muß zweimal gelesen
werden, und der Dekomprimierer benötigt zusätzliche Informationen
für die Dekomprimierung.
• Bei adaptiven Verfahren wird die Codierung für die Komprimierung
und Dekomprimierung während der Komprimierung angepaßt. Die
Datenquelle muß nur einmal gelesen werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
259
6. Textkompression
Allgemeines zur Textkompression
6. Textkompression
Allgemeines Modell der Textkompression
Allgemeines zur Textkompression
Wörterbuchbasierte Verfahren
• Gegeben ist eine Datenquelle s als String über dem Alphabet {0, 1}
(Bitstring).
• Das Dictionary für die Kompression läßt sich bei wörterbuchbasierten
Verfahren darstellen als
• Die Ausgabe c eines Kompressionsverfahrens ist ebenfalls ein Bitstring.
• Weiterhin sei ein Alphabet A gegeben.
D = {(f, c)|f ∈ F, c ∈ {0, 1}∗}
Hierbei ist F eine Teilmenge der Substrings von s.
• Ein Kompressionsverfahren kann mit Hilfe von zwei injektiven Funktionen g und h beschrieben werden, die von A∗ nach {0, 1}∗ abbilden.
• Die f ∈ F übernehmen hier die Rolle der a ∈ A.
• Die Menge {(g(a), h(a))|a ∈ A} wird als Dictionary des Kompressionsverfahrens bezeichnet.
• Die Datenquelle kann als eine Konkatenation von vielen f ∈ F angesehen werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6. Textkompression
260
Allgemeines zur Textkompression
• Die Funktion g gibt im Prinzip an, wie die Bits von s zu interpretieren
sind. g −1 sukzessive angewendet auf s liefert einen String text ∈ A∗.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6. Textkompression
262
Allgemeines zur Textkompression
• Für ein wörterbuchbasiertes Kompressionsverfahren müssen nun die
folgenden Punkte festgelegt werden:
– Man finde eine geeignete Menge F von Substrings von s,
– man bestimme, wie s als Konkatenation von f ∈ F dargestellt wird
(Faktorisierung), und
– man lege die Codierung für die f ∈ F fest.
• Die Funktion h gibt die Codierung der a ∈ A an.
• c entsteht durch sukzessive Anwendung von h auf text.
• Beispiel: Wandlung eines (maschinenlesbaren) Textes in MorseZeichen.
A ist die Menge der Buchstaben. g bildet Buchstaben in den ASCIICode ab. h definiert den Morse-Code, d.h. wie Buchstaben in MorseZeichen codiert werden.
• Bei einer festen Funktion g kann der Algorithmus allein durch h beschrieben werden.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
261
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
263
6. Textkompression
Allgemeines zur Textkompression
6. Textkompression
Optimale Faktorisierung
Lempel-Ziv-Codierung
Gegeben sei ein Wörterbuch. Man bestimme nun eine Faktorisierung
eines Textes, so daß die Gesamtlänge der verwendeten Codes minimal
ist.
f
a
b
ba
bb
abb
Beispiel 6.1.
c
00
010
0110
0111
1
l(c)
2
3
4
4
1
Wie kann damit der Text “babb” optimal faktorisiert werden?
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
• Die bekanntesten wörterbuchbasierten Kompressionsalgorithmen
basieren auf den Verfahren von A. Lempel und J. Ziv (LZ).
• Dies sind adaptive Verfahren, die wie folgt vorgehen:
– Die Menge F wird dynamisch in Abhängigkeit von s während des
Kompressionsvorgangs bestimmt.
– Für die Faktorisierung wird eine sogenannte Greedy-Strategie benutzt, d.h. man bestimmt aus dem aktuellen F jeweils das längste
f , das einen Präfix von s darstellt.
– Als Codierung werden Verweise (Pointer) auf den jeweiligen
Dictionary-Eintrag verwendet.
• Es gibt im Prinzip zwei Familien von Kompressionsalgorithmen, die
auf den Verfahren LZ77 und LZ78 beruhen.
264
6. Textkompression
Allgemeines zur Textkompression
Allgemeines zur Textkompression
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6. Textkompression
• Repräsentation als kürzestes Wege Problem
Faktorisierung und Erstellung des Dictionary bei LZ78:
• Es gibt eine Kante von Knoten i zu Knoten j, wenn text[i . . . j − 1] im
Dictionary auftritt.
Die Länge des zugehörigen Codes bestimmt das Gewicht der Kante.
• Ein kürzester Weg von Knoten 1 nach Kanoten n + 1 repräsentiert
eine optimale Faktorisierung.
1
3
2
3
3
4
3
• In einem beliebigen Iterationsschritt sei s der noch zu komprimierende Rest der Datenquelle.
5
• Ausgegeben wird der Verweis auf den zu f gehörenden DictionaryEintrag und das Zeichen a.
1
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
• Zunächst besteht das Dictionary nur aus dem leeren String .
Man sucht nun für die Faktorisierung im Dictionary das größte f , so
daß gilt: s = f az. Hierbei ist a genau ein Zeichen und z ein beliebiger
String.
4
2
Allgemeines zur Textkompression
LZ78
• Für Text der Länge n werden n + 1 Knoten eingeführt.
4
266
265
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
267
6. Textkompression
Allgemeines zur Textkompression
• Der String f a wird neu in das Dictionary aufgenommen.
6. Textkompression
Allgemeines zur Textkompression
Beispiel 6.2. Es sei s = aababbabbabb. Dies führt zu der Faktorisierung:
• Anschließend verfährt man mit dem Rest z der Datenquelle genauso.
a ab abb abba b b#
• Damit garantiert ist, daß eine Darstellung f az stets möglich ist, fügt
man an s ein Zeichen # an, das in s nicht vorkommt.
Nach Ablauf des Algorithmus liegt das folgende Dictionary vor:
Darstellung der Verweise in LZ78:
k
0
1
2
3
4
5
6
• Es werden Verweise variabler Länge benutzt, wobei die Länge von
der aktuellen Größe des Dictionary abhängt.
• Es sei n die Anzahl der Einträge im Dictionary. Dann gilt für die verwendete Länge l(n) der Verweise:
l(1) = 1 und l(n) = dlog2(n)e für n > 1
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6. Textkompression
Algorithmus 6.1. [LZ78-Kompression]
ste (f0, f1, . . . , fn−1) von Strings.
268
Allgemeines zur Textkompression
Das Dictionary D sei eine Li-
fk
a
ab
abb
abba
b
b#
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
270
6. Textkompression
Allgemeines zur Textkompression
Anschaulich dargestellt ergibt sich die Ausgabe
0a 1b 10b 11a 000b 101#
D := {}
x := s#
while x 6= do
fk := längstes fk ∈ F , so daß x = fk az gilt, mit a ∈ A
a := Zeichen, daß auf fk in x folgt
Ausgabe von k in l(|D|) Bits
Ausgabe von a in Orginalcodierung (z.B. ASCII)
Aufnahme von fk a als f|D| in D
x := z
end
0
a
b
1
Veranschaulichung:
Dictionary
aus
Beispiel 6.1 als Trie
5
b
#
2
6
b
3
a
4
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
269
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
271
6. Textkompression
Allgemeines zur Textkompression
6. Textkompression
Allgemeines zur Textkompression
Bemerkungen:
Implementierungsaspekte
• Es gibt eine Vielzahl von Varianten des LZ78-Algorithmus.
• Entscheidend für die Effizienz von LZ78 ist die schnelle Bestimmung
der fk .
• Hierzu legt man das Wörterbuch in einem Trie ab.
• Jeder Knoten des Tries entspricht einem Dictionary-Eintrag.
• Man liest nun Zeichen für Zeichen von x und steigt, ausgehend von
der Wurzel, sukzessive den Trie hinab.
• Kommt man mit dem letzten gelesenen Zeichen im Trie nicht weiter,
dann entspricht der aktuelle Knoten dem fk , und das letzte gelesene
Zeichen ist das zusätzliche Zeichen a.
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6. Textkompression
272
Allgemeines zur Textkompression
• Zur Erweiterung des Dictionary fügt man ausgehend vom aktuellen
Knoten eine mit a markierte Kante und einen neuen Knoten ein. Der
neue Knoten repräsentiert den Dictionary-Eintrag fk a.
• Diese Varianten unterscheiden sich z.B. in bezug auf:
–
–
–
–
Die Benutzung variabler oder fixer Verweislängen,
die maximale Größe des Dictionary,
das Vorgehen, wenn das Dictionary voll ist und
die Behandlung des einen zusätzlichen Zeichens bei der Faktorisierung.
• Das U NIX-Programm compress, bekannt als LZC, basiert auf LZ78.
Es ist eigentlich hervorgegangen aus LZW, wobei aber viele Aspekte
von LZ78 wieder übernommen wurden, so z.B. die variablen Verweislängen (im Gegensatz zu LZW, das fixe Verweislängen verwendet).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6. Textkompression
274
Allgemeines zur Textkompression
• Laut Manual-Seite reduziert compress Textdateien auf 50 bis 60 %
der Orginalgröße.
• Anschließend springt man wieder an die Wurzel des Tries.
• Das bekannte Kompressionsprogramm gzip basiert im Gegensatz
zu compress auf dem LZ77-Verfahren.
• Gesamtaufwand: O(|s|)
• Bei LZ77 wird
– die Länge der Dictionary-Einträge durch einen Parameter F beschränkt, und
– das Dictionary bezieht sich stets nur auf die letzten N Zeichen.
– Dafür enthält das Dictionary jeden Substring der letzten N − F
Zeichen mit der maximalen Länge F .
– Typische Werte für N und F : 10 ≤ F ≤ 20, N ≤ 8192
• In der Praxis hat sich LZ77 (gzip) als etwas besser erwiesen als
LZ78 (compress).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
273
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
275
6. Textkompression
Allgemeines zur Textkompression
• LZ78 hat aber
– die besseren theoretischen Eigenschaften und
– die beste bekannte Variante von LZ78 ist besser als die beste bekannte LZ77-Variante.
6. Textkompression
Allgemeines zur Textkompression
• Es wird nun nach einer Position innerhalb der ersten N − F Zeichen
nach einem größtmöglichen Match maximal der Länge F für den Beginn des lookahead buffers gesucht.
Beispiel: Position 10, String bab
• Ausgegeben wird nun:
– Die Startposition innerhalb des ersten Teils
– Die Länge des Match
– Das erste Zeichen, das nicht auf den Match passte
• Anschließend wird das Fenster um j +1 Zeichen nach rechts geschoben.
• Typische Werte für N und F : 10 ≤ F ≤ 20, N ≤ 8192
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
276
6. Textkompression
Allgemeines zur Textkompression
• Die ersten N − F Zeichen dieses Fensters wurden bereits codiert.
• Die verbleibenden F Zeichen sind der sogenannte lookahead buffer.
5
6
7
8
9 10 11 12 13 14 15
b
c
b
a
c
bereits kodiert
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
Allgemeines zur Textkompression
• Zu Beginn sind die ersten N − F Zeichen Leerzeichen und der lookahead buffer enthält die ertsen F Zeichen des Textes.
• Über den Text wird ein Fenster der Größe N geschoben.
a
6. Textkompression
278
• Für die Verweise in das Dictionary und die Längenangabe werden
konstante Längen benutzt.
LZ77
b
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
b
a
b
Decodierung:
• Der Decoder verwaltet ein Fenster der gleichen Größe wie der Kodierer.
• Durch die Verweise wird der lookahead buffer gefüllt und das Fenster
nach rechts geschoben.
c
lookahead buffer
277
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
279
6. Textkompression
Allgemeines zur Textkompression
Vergleich der Verfahren
Siehe: T. C. B ELL, J. G. C LEARY und I. H. W ITTEN: Text Compression.
Durchschnittliche Anzahl an Bits der komprimierten Datei pro Byte der
Datenquelle:
Verfahren
Huffman
LZ77
LZB
LZ78
LZC
LZFG
Bits pro Byte der Quelle
4.99
3.94
3.18
4.13
4.26
2.95
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
6. Textkompression
280
Allgemeines zur Textkompression
LZB ist die beste LZ77-Variante, LZFG die beste LZ78-Variante.
Die Werte wurden auf der Basis einer umfangreichen heterogenen Dokumentkollektion ermittelt (u.a. troff-Texte, ausführbare Programme,
ASCII-Texte, Programmquellen, wissenschaftliche Daten, etc.).
Textalgorithmen — FH Bonn-Rhein-Sieg, SS 02
281
Herunterladen