Betriebssysteme - Werkzeuge und UNIX-Schnittstelle
==================================================
Werkzeuge
=========
6. Reguläre Ausdrücke
=====================
Reguläre Ausdrücke - ein Gespenst geht um im Unix.
|
| next | back | 2017 - 1 | Fri Apr 7 14:46:38 CEST 2017 |
Was ist ein regulärer Ausdruck (Wikipedia): Ein regulärer Ausdruck (englisch regular expression, Abkürzung: Regex) ist in der Informatik eine Zeichenkette, die der Beschreibung von Mengen von Zeichenketten mit Hilfe bestimmter syntaktischer Regeln dient. Reguläre Ausdrücke finden vor allem in der Softwareentwicklung Verwendung. Neben Implementierungen in vielen Programmiersprachen verfügen auch viele Texteditoren über reguläre Ausdrücke in der Funktion "Suchen und Ersetzen". Ein einfacher Anwendungsfall von regulären Ausdrücken sind Wildcards. Reguläre Ausdrücke können als Filterkriterien in der Textsuche verwendet werden, indem der Text mit dem Muster des regulären Ausdrucks abgeglichen wird. Dieser Vorgang wird auch Pattern Matching genannt. Zur Implementierung von regulären Ausdrückeng werden deterministische finite (endliche) Automaten (DFA) oder nichtdeterministische finite (endliche) Automaten (NFA) benutzt. |
| next | back | 2017 - 2 | Fri Apr 7 14:46:38 CEST 2017 |
Wo werden reguläre Ausdrücke benutzt?
Programm Autor Implementierung
awk Aho, Weinberger, Kernighan DFA
new awk Kernighan DFA
GNU awk A.Robbins DFA/NFA
MKS awk Mortice Kern Systems Posix-NFA
mawk M. Brennan Posix-NFA
egrep Aho DFA
MKS egrep Mortice Kern Systems Posix-NFA
expr D.Haight NFA
grep K.Thompson NFA
GNU grep M.Haertel DFA/NFA
GNU find GNU NFA
more E.Schienbrood NFA
perl L.Wall NFA
Python G.v.Rossum NFA
sed Lee McMahon NFA
Tcl John Ousterhout NFA
vi Bill Joy NFA
DFA - Deterministischer Finiter (endlicher) Automat
NFA - Nichtdeterministischer Finiter (endlicher) Automat
|
| next | back | 2017 - 3 | Fri Apr 7 14:46:38 CEST 2017 |
DFA
---
"Textgesteuert" - geht vom Text aus und prüft, ob der Ausdruck passt
Vorteile: Schnell, nicht von der Programmierung des Ausdrucks abhängig
POSIX-Konform
Nachteile: Keine Klammern, Keine Rückwärtsreferenzen
NFA
---
"Ausdrucksgesteuert" - geht vom Ausdruck aus und prüft ob der Text passt
Vorteil: der Programmierer kann durch die Gestaltung des Ausdrucks die
Arbeitsweise des Suchens bestimmen,
leistungsstärker, da Klammern unterstützt werden
Nachteil: nicht immer POSIX-Konform, verschiedene Implementierung liefern
unterschiedliche Ergebnisse, eventuell langsamer, da Backtracking
POSIX
-----
Verlangt die Lieferung des "längsten frühesten Treffers", Klammern optional
Regulärer Ausdruck:
Allgemeine Notation zur Beschreibung von Textmustern
bestehend aus Zeichen des Codes und Metazeichen
Muster:
'Müller' - die Zeichenkette 'Müller'
'^Bell ' - 'Bell' am Zeilenanfang
' Bell$' - 'Bell' am Zeilenende
'^[ ]*$' - <leere Zeilen>
'\<([a-zA-Z]+)\> +\<\1\>' - doppelte Wörter in einem Text
'^(From|Subject): ' - 'From:' oder 'Subject:' am Zeilenanfang
|
| next | back | 2017 - 4 | Fri Apr 7 14:46:38 CEST 2017 |
Metazeichen
-----------
Metazeichen sind Zeichen, die eine spezielle Funktion haben.
Sollen sie diese Funktion nicht haben, muessen sie mit '\' maskiert werden.
Einzelkämpfer:
^ - Kennzeichnet den Zeilenanfang (Zeilenanker)
/^Bell / beschreibt ein Muster, bei dem das Wort "Bell" am
Zeilenanfang steht und von einem Leerzeichen gefolgt
wird.
Beispiel: b1
echo "Bell hat gruene Haare" | grep "Bell"
echo "Der Bell hat gruene Haare" | grep "Bell"
echo "Bell hat gruene Haare" | grep "^Bell"
echo "Der Bell hat gruene Haare" | grep "^Bell"
$ - Kennzeichnet das Zeilenende (Anker, Begrenzer)
/ Bell$/ beschreibt ein Muster, bei dem das Word "Bell" am
Zeilenende stehr und vor dem ein Leerzeichen positioniert
ist.
Beispiel: b2
echo "Wer hat gruene Haare? Bell" | grep "Bell"
echo "Wer hat gruene Haare? alle Bells" | grep "Bell"
echo "Wer hat gruene Haare? Bell" | grep "Bell$"
echo "Wer hat gruene Haare? alle Bells" | grep "Bell$"
echo 'Bell$ hat gruene Haare' | grep '^Bell$'
echo 'Bell$ hat gruene Haare' | grep '^Bell\$'
|
| next | back | 2017 - 5 | Fri Apr 7 14:46:38 CEST 2017 |
Ein universeller Einzelkämpfer:
. - Der Punkt kennzeichnet ein beliebiges Zeichen
/Schmid./ beschreibt ein Muster, bei dem das Wort "Schmid" von
einem beliebigen Zeichen gefolgt werden kann, also
"Schmidt", "Schmid ", "Schmidx"
Beispiel: b3
echo "Schmidt hat gruene Haare" | grep "Schmid."
echo "Schmid hat gruene Haare" | grep "Schmid. "
echo "Schmidx hat gruene Haare" | grep "Schmid. "
Pärchen:
\< - Kennzeichnet den Wortanfang (Wortanker)
/\<Bell/ beschreibt ein Muster, bei dem die Zeichekette "Bell" am
Wortanfang erkannt wird. Zeilenanfang ist auch ein
Wortanfang.
Beispiel: b4
echo "Bell hat gruene Haare" | grep "Bell"
echo "DerBell hat gruene Haare" | grep "Bell"
echo "Der Bell hat gruene Haare" | grep "Bell"
echo "Bell hat gruene Haare" | grep "\<Bell"
echo "DerBell hat gruene Haare" | grep "\<Bell"
echo "Der Bell hat gruene Haare" | grep "\<Bell"
|
| next | back | 2017 - 6 | Fri Apr 7 14:46:38 CEST 2017 |
\> - Kennzeichnet das Wortende (Anker, Begrenzer)
/Das\>/ beischreibt ein Muster, bei dem die Zeichenkette "Das" am
Wortende erkannt wird. Zeilenende ist auch ein
Wortende.
Beispiel: b5
echo "Wer hat gruene Haare? Bell" | grep "Bell"
echo "Wer hat gruene Haare? alle Bells" | grep "Bell"
echo "Wer hat gruene Haare? Bell" | grep "Bell\>"
echo "Wer hat gruene Haare? alle Bells" | grep "Bell\>"
Paarkämpfer - Mengen von Zeichen
[...] - verlangt ein Zeichen aus der beschriebenen Menge,
'b[ea]ll' kennzeichnet die Worte 'bell' und 'ball'
Beispiel: b6
echo "Bell hat gruene Haare" | grep "Bell"
echo "Der Ball ist rund" | grep "Bell"
echo "Bell hat gruene Haare" | grep "Ball"
echo "Der Ball ist rund" | grep "Ball"
echo "Bell hat gruene Haare" | grep "B[ae]ll"
echo "Der Ball ist rund" | grep "B[ae]ll"
|
| next | back | 2017 - 7 | Fri Apr 7 14:46:38 CEST 2017 |
[^...] - verlangt Zeichen, die nicht aus der beschriebenen Menge stammen,
'b[ea]ll' kennzeichnet die Worte 'bbll', 'bcll', ..
aber nicht 'bell' und 'ball'
Beispiel: b7
echo "Bell hat gruene Haare" | grep "Bell"
echo "Der Ball ist rund" | grep "Ball"
echo "Bolle ist auch ok" | grep "Bell"
echo "Bolle ist auch ok" | grep "Ball"
echo "Bell hat gruene Haare" | grep "B[^ae]ll"
echo "Der Ball ist rund" | grep "B[^ae]ll"
echo "Bolle ist auch ok" | grep "B[^ae]ll"
Mengen von Zeichen lassen sich auch verkürzt schreiben:
[a-zA-z] beschreibt alle Klein- und alle Großbuchstaben.
z.B: [0-9a-z], [0-9_!.?]
Beispiel: b8
echo "Bell hat gruene Haare!" | grep "B[a-z]ll"
echo "Boll hat gruene Haare!" | grep "B[a-z]ll"
echo "Bill hat gruene Haare!" | grep "B[a-z]ll"
echo "BOll hat gruene Haare!" | grep "B[a-z]ll"
echo "Bell hat gruene Haare," | grep "[!,]$"
echo "Bell hat gruene Haare!" | grep "[!,]$"
echo "Bell hat gruene Haare" | grep "[!,]$"
|
| next | back | 2017 - 8 | Fri Apr 7 14:46:38 CEST 2017 |
Häufigkeiten
? - Kennzeichnet, das das vorangestellte Zeichen oder ein Zeichen aus
der vorangestellten Zeichenklasse ein- oder keinmal in der
Zeichenkette auftreten kann.
Beispiel: b9, b9a
echo "Bell kann man mit zwei l schreiben" | grep "Bell\>"
echo "Bel kann man auch mit einem l schreiben" | grep "Bell\>"
echo "Belll kann man auch mit 3 l schreiben." | egrep "Bell?\>"
echo "Bell kann man mit zwei l schreiben" | grep "Bell?\>"
echo "Bel kann man auch mit einem l schreiben" | grep "Bell\>"
echo "Belll kann man auch mit 3 l schreiben." | egrep "Bell?\>"
+ - Kennzeichnet, das das vorangestellte Zeichen oder ein Zeichen aus
der vorangestellten Zeichenklasse ein- oder mehrmals in der
Zeichkette auftreten kann.
Beispiel: b10
echo "Bell kann man mit zwei l schreiben" | grep "Bell\>"
echo "Bel kann man auch mit einem l schreiben" | grep "Bell\>"
echo "Belll kann man auch mit 3 l schreiben." | egrep "Bell\>"
echo "Bell kann man mit zwei l schreiben" | grep "Bel+\>"
echo "Bel kann man auch mit einem l schreiben" | grep "Bel+>"
echo "Belll kann man auch mit 3 l schreiben." | egrep "Bel+\>"
|
| next | back | 2017 - 9 | Fri Apr 7 14:46:38 CEST 2017 |
* - Kennzeichnet, das das vorangestellte Zeichen oder ein Zeichen aus
der vorangestellten Zeichklasse 0 oder n-mal in der Zeichkette
autreten kann.
Beispiel: b11
echo "Bell kann man mit zwei l schreiben" | grep "Bell\>"
echo "Bel kann man mit zwei l schreiben" | grep "Bell\>"
echo "Belll kann man auch mit 3 l schreiben." | egrep "Bell\>"
echo "Be kann man auch ohne l schreiben." | egrep "Bell\>"
echo "Bell kann man mit zwei l schreiben" | grep "Bel+\>"
echo "Bel kann man auch mit einem l schreiben" | grep "Bel*>"
echo "Belll kann man auch mit 3 l schreiben." | egrep "Bel*\>"
echo "Be kann man auch ohne l schreiben." | egrep "Bel*\>"
echo "Be kann man auch ohne l schreiben." | egrep "Be[xl]*\>"
echo "Bexx kann man auch mit xx schreiben." | egrep "Be[xl]*\>"
echo "Bex kann man auch mit x schreiben." | egrep "Be[xl]*\>"
|
| next | back | 2017 - 10 | Fri Apr 7 14:46:38 CEST 2017 |
Gruppierungen
(...) - durch eine Gruppierung kann man mehrer Zeichen zu einer Gruppe
zusammenfassen und für diese Gruppe dann weitere Eigenschaften
(z.B. Häufigkeiten) festlegen.
Beispiel: b12
echo "xxab soll gefunden werden" | egrep "xxab"
echo "xx soll auch gefunden werden" | egrep "xx"
echo "xxab soll gefunden werden" | egrep "xx(ab)?"
echo "xx soll gefunden werden" | egrep "xx(ab)?"
Alternativen
| - trennt Suchmuster, bei dem jedes für sich allein die
Suchbedingung erfüllt.
Beispiel: b13
echo "abxx soll gefunden werden" | egrep "abxx"
echo "abyy soll gefunden werden" | egrep "abyy"
echo "abzz soll gefunden werden" | egrep "abzz"
echo "abxx soll gefunden werden" | egrep "ab(xx|yy|zz)"
echo "abyy soll gefunden werden" | egrep "ab(xx|yy|zz)"
echo "abzz soll gefunden werden" | egrep "ab(xx|yy|zz)"
|
| next | back | 2017 - 11 | Fri Apr 7 14:46:38 CEST 2017 |
Weitere Funktion von Klammern:
Speichern von "gematchten" Texten
Ein durch runde Klammern eingeschlossener Text kann später im Suchmuster
noch- einmal benutzt werden. Diese Rückwärtsreferenzen werden durch
'\1', '\2', u.s.w. spezifiziert. Die Klammerpärchen werden durch-
nummerriert. Maximal 9 Rückwärtsreferenzen möglich.
Beispiel: \<([a-zA-Z]+)\> +\<\1\> b14
echo "das das ist nicht schön" | egrep '\<([a-zA-Z]+)\> +\<\1\>'
echo "das ist nicht schön" | egrep '\<([a-zA-Z]+)\> +\<\1\>'
echo "ist das alles alles nicht schön" | egrep '\<([a-zA-Z]+)\> +\<\1\>'
echo "ist das alles nicht schön" | egrep '\<([a-zA-Z]+)\> +\<\1\>'
echo "und jetzt etwas weiter etwas" | \
egrep '\<([a-zA-Z]+)\> +\<([a-zA-Z]+)\> +\<\1\>'
echo 'und jetzt etwas weiter etwas' | \
egrep '\<([a-zA-Z]+)\> +\<([a-zA-Z]+)\> +\<\2\>'
echo 'und jetzt etwas weiter weiter' | \
egrep '\<([a-zA-Z]+)\> +\<([a-zA-Z]+)\> +\<\2\>'
echo 'und und jetzt etwas weiter' | \
egrep '\<([a-zA-Z]+)\> +\<([a-zA-Z]+)\> +\<\2\>'
|
| next | back | 2017 - 12 | Fri Apr 7 14:46:38 CEST 2017 |
1.Zusammenfassung
-----------------
Metazeichen Bezeichnung Bedeutung
Anker
^ Zirkumflex, Dach Zeilenanfang
$ Dollarzeichen Zeilenende
\< Backslash Kleinerzeichen Position am Wortanfang
\> Backslash Größerzeichen Position am Wortende
Zeichenklassen
. Punkt irgendein Zeichen
[...] Zeichenklasse irgendein Zeichen aus der Menge
[^...] verneinte Zeichenklasse irgendein Zeichen nicht aus der Menge
Gruppierungen
| Pipe Alternation
(...) runde Klammern Beschränkung der Reichweite von "|"
Häufigkeiten
? Fragezeichen vorangestellte Zeichen vorhanden oder nicht
+ Plus vorangestellte Zeichen ein- oder mehrmals
* Stern 0-n Mal das vorangestellte Zeichen
Wiederholungen
\1, \2 Rückwärtsreferenzen vorheriges Auftreten eines () Ausdrucks
|
| next | back | 2017 - 13 | Fri Apr 7 14:46:38 CEST 2017 |
Wo gibt es was?
Feature grep egrep awk vi perl
*,^,$,[...] x x x x x
?,+,| \? \+ \| ? + | ? + | \? \+ ? + |
\(...\) x (...) (...) x (...)
\<,\> - x - - x
Rückwärtsreferenz x - - x x
Einige einfache Aufgaben:
1. Entfernen aller Leerzeilen aus einem Text.
1. Versuch
sed '/^$/d' file
Problem: Leerzeichen
2. Versuch
sed '/^ $/d' file m1,m1a,m1b,m1c
Problem: mehrere Leerzeichen, kein Leerzeichen
3. Versuch
sed '/^ *$/d' file
Problem: Tabulatoren
4. Versuch
sed '/^[ ]*$/d' file
<Leerzeichen><Tabulator>
m2,m2a,m2b,m2c
|
| next | back | 2017 - 14 | Fri Apr 7 14:46:38 CEST 2017 |
2. Ein etwas exotischer regulärer Ausdruck zum Suchen
von zwei aufeinanderfolgenden Zeichen (XX):
/X(.+)*X/
#!/bin/sh
echo "Eingabe: =XX================================"
echo " Test fuer egrep"
echo egrep "X(.+)+X"
echo "=XX================================" | egrep "X(.+)+X"
echo egrep "X(.+)*X"
echo "=XX================================" | egrep "X(.+)*X"
echo " Test fuer awk "
echo awk "/X(.+)+X/{ print }"
echo "=XX================================" | awk "/X(.+)+X/{ print }"
echo awk "/X(.+)*X/{ print }"
echo "=XX================================" | awk "/X(.+)*X/{ print }"
echo " Test fuer sed"
echo sed "s/X(.+)+X//"
echo "=XX================================" | sed "s/X(.+)+X//"
echo sed "s/X(.+)*X//"
echo "=XX================================" | sed "s/X(.+)*X//"
Wir sehen: Reguläre Ausdrücke sind nicht gleich reguläre Ausdrücke!!!!!
machine
|
| next | back | 2017 - 15 | Fri Apr 7 14:46:38 CEST 2017 |
Weitere Metazeichen
-------------------
Anker
\w - Wortbestandteil: Klasse [a-zA-Z0-9] oder [a-zA-Z0-9_]
\W - Nicht-Wortbestandteil: Klasse [^a-zA-Z0-9] oder [^a-zA-Z0-9_]
Abkürzungsmetazeichen
---------------------
\x<hex> - Hexadezimal-Escapes: \x00..\xff
\<okt> - Oktal-Escapes: \000..\377
\a - Alarm: 007
\b - Backspace: 010 oder Metazeichen für Wortgrenze
\d - Ziffer: [0-9]
\D - nicht Ziffer: [^0-9]
\e - Escape: 010
\f - FormFeed - Seitenvorschub: 014
\n - NewLine - Zeilenvorschug: 012
\r - Wagenrücklauf: 015
\t - Horizontaltabulator: 011
\v - Vertikaltabulator: 013
\s - Whitespace-Zeichen: [ \f\b\r\t\v]
\S - kein Whitespace-Zeichen: [^ \f\b\r\t\v]
|
| next | back | 2017 - 16 | Fri Apr 7 14:46:38 CEST 2017 |
Zeichenklassen
--------------
[:alnum:] - Alphanumerische Zeichen oder Ziffern
[:alpha:] - Alphanumerische Zeichen
[:blank:] - Leerzeichen oder Tabulator
[:cntrl:] - Control-Zeichen
[:digital:] - Ziffern
[:graph:] - Graphische Zeichen
[:lower:] - Kleinbuchstaben
[:print:] - druckbare Zeichen
[:punct:] - Satzzeichen
[:space:] - Whitespace, Tabulatoren, Leerzeichen
[:upper:] - Großbuchstaben
[:xdigit:] - Hexadezimalziffern
bei einigen Programmen auch als: [[: .... :]] kodiert!!!
Neue Häufigkeiten: Intervalle
-----------------------------
{min,max} oder \{min,max\}
{genau} oder \{genau \}
m3
|
| next | back | 2017 - 17 | Fri Apr 7 14:46:38 CEST 2017 |
Probleme:
---------
- Gierigkeit von: .+ und .*
HTML-Text:
<B>fetter Text</B>nicht fetter Text <B> fetter Text </B>
Ausdruck bilden der <B>fetter Text</B> "matched"??
'<B>.*</B>' tut es nicht!!! nicht trivial,
.* ist gierig und geht bis zum letzten Zeichen und dann rückwärts
(Backtracking).
- Reichweite von Klammern:
".*" - nichts
(".*") - Strings einschließlich "
"(.*)" - Text zwischen den Anführungszeichen
"(.)*" - Letztes Zeichen des Textes
m4,m4a,m4b
|
| back | 2017 - 18 | Fri Apr 7 14:46:38 CEST 2017 |