homeUnix & Internet Unix & Shell-Programmierung: Reguläre Ausdrücke Prof. Dr. Uwe Schmidt FH Wedel

Reguläre Ausdrücke

weiter

weiter

Suchen und Ersetzen in Texten

Textmuster
mit regulären Ausdrücken beschreibbar
weiter
merke
viele syntaktische Varianten
weiter
merke
Ausdruckskraft und Mächtigkeit der Muster unterschiedlich
weiter
sh, csh, bash
nur eingeschränkte Suchmuster: wildcards
weiter
grep, sed
einfache Suchmuster
weiter
grep -E
egrep
Standardsuchmuster
weiter
perl, tcl, python, ruby
alles, was mit regulären Ausdrücken möglich ist
weiter

weiter

einfache Filter für automatische Textverarbeitung

cat
kopieren
(neutrales Element bezüglich | )
sort
zeilenweise sortieren
grep
suchen
Global Regular Expression Print
tr
zeichenweises Übersetzen
uniq
doppelte aufeinanderfolgende Zeilen löschen
pr
Druckaufbereitung: Zeilennummern, Seiteneinteilung
wc
Zeichen, Wörter und Zeilen zählen
cut
Spalten selektieren
weiter
sed
stream editor
awk
text editor
sh, csh, bash, tcl, perl
Skriptsprachen für komplexe eigene Filter
weiter
lex, flex
Scanner Generatoren
weiter
merke
in vielen dieser Filter werden reguläre Ausdrücke an zentraler Stelle eingesetzt
weiter

weiter

Grundlagen: Reguläre Ausdrücke

Definition
einer regulären Sprache (regulären Menge) über einem Alphabet A
weiter
.1
mit einer rechtslinearen Grammatik
weiter
.2
mit einem endlichen Automaten (Akzeptor)
weiter
.3
mit einem regulären Ausdruck
weiter

weiter

Reguläre Mengen

Reguläre Mengen
über einem Alphabet A
weiter
Bildungsgesetze
weiter
{ }
leere Menge ist eine reguläre Menge
weiter
{ε}
Menge mit dem leeren Wort
weiter
{a}
alle einelementigen Mengen mit Elementen aus dem Alphabet A
weiter
N ∪ M
Vereinigung zweier regulärer Mengen
weiter
N · M
Konkatenation
weiter
M*
beliebig oft wiederholte Konkatenation
weiter
Bildungsgesetzte
dürfen nur endlich oft angewendet werden
weiter
merke
alle so gebildeten Mengen sind reguläre Mengen (reguläre Sprachen)
weiter
merke
kein Mengendurchschnitt
keine Mengensubtraktion
weiter

weiter

Notation

Reguläre Ausdrücke
Notation zur Beschreibung von regulären Mengen
weiter
Korrespondenz
reg. Ausdruckreg. Menge
Ø{}
 {ε}
a{a}
n | mN ∪ M
nmN · M
m*M*
(n)N
weiter
merke
minimale Menge von Operatoren zur Beschreibung aller regulären Mengen
weiter
merke
in Filtern Erweiterungen, Abkürzungen, Einschränkungen, Syntaxunterschiede
weiter

weiter

Beispiele

Binärzahlen
ohne führende 0-en

A = {0,1}

L(A) = {0, 1, 10, 11, 100, 101, 110, ...}

weiter
reg. Ausdruck
0|(1(0|1)*)
weiter
Dezimalzahlen
A = ASCII-Zeichensatz
weiter
reg. Ausdruck
(0|1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9)*
weiter
merke
abkürzende Schreibweise sinnvoll
weiter

weiter

Abkürzungen

[abc]
(a|b|c)
weiter
[0-9]
(0|1|2|3|4|5|6|7|8|9)
weiter
Beispiele
[0123456789]
[0-9]
[0-9A-Za-z]
[-+0-9.]
[.]
weiter
[^abc]
ein beliebiges Zeichen außer a,b und c
weiter
[^0-9]
ein beliebiges Zeichen nicht aus dem Intervall 0 bis 9
weiter
Beispiele
[^^]
[^.]
[^0-9]
[^0-9A-Za-z]
weiter
merke
keine Mengensubtraktion eingeführt
 
[^5]
entspricht
(...|1|2|3|4|6|7|8|9|...)
weiter
.
ein Punkt: ein beliebiges Zeichen
weiter
merke
manchmal auch ein beliebiges Zeichen außer Zeilenumbruch (\n)
weiter
Beispiele
a.c
...
weiter
\z
Maskieren von Metazeichen (quoting)
Verhinderung der Interpretation als regexp-Operator
weiter
\.
ein Punkt
\\
ein \
\[
eine [
\]
eine ]
\*
ein *
\|
ein |
\(
eine (
\)
eine )
\n
ein Zeilevorschub
\t
ein Tabulatorzeichen
weiter
merke
Maskieren (quoting) nur außerhalb von [ und ] notwendig
weiter
e?
(e|)
weiter
e+
(e)(e)*
weiter
e{n}
  • n=0: ()
  • n>0: (e)(e{n-1})
e{n,}
  • n=0: (e)*
  • n>0: (e)(e{n-1,})
e{n,m}
  • n <=m
  • n=0, m=0: ()
  • n=0, m>0: (e?)(e{0,m-1})
  • n>0, m>0: (e)(e{n-1,m-1})
Beispiele
ab?c
(ab)?c
..?
[0-9][0-9]?
weiter
Beispiele
mit + und *
 
a*
.*
[ ]*
.*a
a+
[ ]+
weiter
Beispiele
mit {n}, {n,} und {n,m}
 
a{5}
a{5,}
a{5,7}
.{5,7}
(a|b{2}){1,2}
weiter
Übungen
Zeitangaben
Stundenangabe in einem Text erkennen:
Alle ein- oder zweistelligen Zahlen zwischen 0 und 23 mit optional einer führenden 0
weiter
HTML tags
<H1> tags finden
<H1> tags ohne Groß- und Kleinschreibung
<H1> tags mit Zwischenräumen
<H1> tags mit whitespace
alle H-tags
weiter

weiter

Kontextbeschreibungen

Zeilenanfang
^
Zeilenende
$
Wortanfang
\<
Wortende
\>
weiter
Beispiele
^Date:
//.*$
\<ding
\<ding\>
weiter
grep -E
egrep
suchen
extended grep
weiter
Syntax
grep -E [option...] muster [datei...]
oder
egrep [option...] muster [datei...]
weiter
merke
Vorsicht: grep verlangt \( anstatt ( für Prioritätenklammern,
bei grep -E oder egrep ist ( Prioritätenklammer und \( das Zeichen (
Optionen
-i
ignoriere Groß- und Kleinschreibung
-n
Ausgabe von Dateiname und Zeilennummer
weiter
Beispiele
egrep -i '<H1' `find . -name '*.html'`
egrep -i '\<UNIX\>' ...
 
weiter
syntaktische Varianten
sh, bashgrep, sedegrep, tcl, perl
[abc][abc][abc]
[0-9][0-9][0-9]
 [^abc][^abc]
?..
*.*.*
  (...|...)
  \< ... \>
  (...)?
  (...)+
weiter
merke
weitere Varianten: sed und emacs \( anstatt (

weiter

Suchen und Ersetzen

sed
stream editor
weiter
Syntax
sed -e Kommando [-e Kommando ...] [datei...]
weiter
Substitution
's|suchmuster|ersetzung|modifier'
weiter
Beispiel
sed -e 's|r|l|g' -e 's|R|L|g'
 
oder
 
sed -e 's|r|l|g' | sed -e 's|R|L|g'
weiter
Referenzieren
von Teilzeichenreihen
 
(...(...)...(...))
 
Klammerpaare durchnummeriert mit
 
\i
 
Zeichenreihe, die auf das i-te Klammerpaar passt, referenzieren
weiter
Beispiel
ersetzen von //... Kommentar durch /*...*/ Kommentar
 
sed -e 's|//\(.*\)$|/*\1*/|'
Beispiel
//... Kommentare löschen
 
sed -e 's|//.*$||'
weiter
perl
als sed Ersatz
 
perl -p -e Kommando
 
mit allen Möglichkeiten der regulären Ausdrücke in perl
weiter
Beispiel
ersetzen von //... Kommentar durch /*...*/ Kommentar
 
perl -p -e 's|//(.*)$|/*\1*/|'

weiter

Beispiel mit bash, grep, sort, tr, ...

grep
# alle symbolic links suchen
 
ls -l /usr/bin | grep '^l'
 
# alle allg. lesbare und schreibbare Geraete
 
ls -l /dev | grep '^.......rw'
 
# Dateien nach Laenge sortiert listen
 
ls -l | sort -k 5 -n
weiter
merke
alles kleine Programme
weiter
tr
zeichenweise übersetzen
weiter
Syntax
tr tabelle1 tabelle2
weiter
Beispiele
# alles gross
 
tr a-z A-Z
 
# alles klein
 
tr A-Z a-z
 
# alle Rs raus
 
tr rR lL
 
# alle Namen klein
 
for i in *[A-Z]*
do
    mv $i `echo $i | tr A-Z a-z`
done
 
# alle Woerter eines Textes
 
tr -sc A-Za-z '\012'
 
# "chinesisches" Handbuch (Plattwitz)
 
man tr | tr rR lL
 
# Handbuch nach Ernst Jandl
 
man tr | tr rRlL lLrR
 
# Geheimschrift
 
tr a-z  b-za     # kodieren
tr b-za a-z      # dekodieren
 
# Raeubersprache
 
rev              # Zeichen einer Zeile umdrehen
 
tac              # reverse cat
weiter
rot13
#!/bin/bash
cat "$@" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
jandln
#!/bin/bash
 
# alle Texte nach Jandl uebersetzen
cat "$@" | tr rRlL lLrR
Ausprobieren
mit
 
        lichtung
 
    manche meinen
    lechts und rinks
    kann man nicht velwechsern
    werch ein illtum!
weiter
 
weiter

weiter

weitere Filter

rev
Zeichen einer Zeile umdrehen
weiter
tac
Zeilen eines Textes umdrehen
reverse cat
weiter
cut
Spalten aus einem Text selektieren
weiter
Syntax
cut -d delimiter -f field
weiter
Beispiel
echo abc def ghi | cut -d ' ' -f 2
cut -d : -f 5 /etc/passwd
weiter

weiter

Beispiel: cross reference list

Filter und pipes
kurze Entwicklungszeit
schrittweise Verfeinerung
lange Laufzeit
weiter
Aufgabe
crossreference list für die Identifikatoren in einem C-Programm
weiter
.1
alle Identifkatoren finden
.2
alle Zeilennummern zu einem Identifikator finden
.3
formatieren
weiter
.1.1
alle Wörter finden, Sonderzeichen löschen
.1.2
Zahlen löschen
.1.3
Schlüsselwörter löschen
weiter
.2.1
Identifikatoren suchen: egrep
.2.2
aus egrep-Ausgabe Zeilennummern extrahieren
weiter
.1.3.1
ckeywords erzeugt Liste aller C-Schlüsselwörter
.1.3.2
Mengenoperationen mit sort und uniq simulieren
weiter
Lösung
weiter
woerter
#!/bin/bash
 
cat "$@" \
  | tr -sc A-Za-z '\012'
weiter
identifier0
#!/bin/bash
# alle Identifier aus einem C Programm
 
cat "$@" \
  | tr -sc A-Za-z_0-'\012' \
  | sort -u
weiter
identifier1
#!/bin/bash
# alle Identifier aus einem C Programm
 
cat "$@" \
  | tr -sc A-Za-z_0-'\012' \
  | sed 's|^[0-9].*$||' \
  | sort -u
weiter
identifier
#!/bin/bash
# alle Identifier aus einem C Programm
# ohne Schluesselwoerter
 
{  cat "$@" \
    | tr -sc A-Za-z_0-'\012' \
    | sed 's|^[0-9].*$||' \
    | sort -u
  ckeywords
  ckeywords
} | sort \
  | uniq -u
weiter
merke
Dieses Skript funktioniert nur wenn ckeywords ein gültiges Kommando ist, also wenn ckeywords über PATH erreichbar ist
merke
Momentanes Arbeitsverzeichnis im Pfad?
identifier2
#!/bin/bash
# alle Identifier aus einem C Programm ohne Schluesselwoerter
 
which ckeywords 2>/dev/null || \
 { echo "$0: program ckeywords not found" 1>&2
   exit 1
 }
 
{ cat "$@" \
    | tr -sc A-Za-z_0-'\012' \
    | sed 's|^[0-9].*$||' \
    | sort -u
    ckeywords
    ckeywords
} \
    | sort \
    | uniq -u
weiter
gut
Defensive Programmierung
Test, ob ckeywords zur Verfügung steht.
ckeywords
#!/bin/bash
# alle C Schluesselwoerter
 
function ckeywords () {
  cat << 'ende keywords'
auto
break
case
char
const
continue
default
do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
 
ende keywords
}
 
ckeywords
 
weiter
zeilennummern
#!/bin/bash
 
ident=$1
shift
 
cat "$@" \
  | grep -n -E "\<$ident\>" \
  | sed 's|:.*$||' 
weiter
crossref
#!/bin/bash
 
file="$1"
 
for id in $(identifier "$file")
do
   echo "$id"
   zeilennummern "$id" "$file" \
     | pr --b -t
   echo ""
done
weiter
schlecht
Skript ist verteilt auf mehrere kleine Dateien
weiter
gut
Funktionen ausnutzen
weiter
cross
#!/bin/bash
 
# Kreuzreferenz-Liste fuer Bezeichner in C-Programmen
# $1 : C Datei
 
# ------------------------------
 
# alle C Schluesselwoerter
 
function ckeywords () {
  cat << 'ende keywords'
auto
break
case
char
const
continue
default
do
double
else
enum
extern
float
for
goto
if
int
long
register
return
short
signed
sizeof
static
struct
switch
typedef
union
unsigned
void
volatile
while
 
ende keywords
}
 
# ------------------------------
 
# alle Bezeichner aus einem C Programm
# ohne Schluesselwoerter
 
function identifier () {
    (
    cat "$1" \
    | tr -sc A-Za-z_0-'\012' \
    | sed 's|^[0-9].*$||' \
    | sort -u
 
    ckeywords
    ckeywords
    ) \
    | sort \
    | uniq -u
 
}
 
# ------------------------------
 
function zeilennummern () {
    local ident
 
    ident=$1
    shift
 
    cat "$@" \
    | grep -n "\<$ident\>" \
    | sed 's|:.*$||' 
}
 
# ------------------------------
 
# das "Hauptprogramm"
 
file="$1"
 
for id in $(identifier "$file")
do
   echo $id
   zeilennummern $id "$file" \
     | pr --b -t
   echo ""
done
 
# ------------------------------
 
weiter

Letzte Änderung: 10.11.2014
© Prof. Dr. Uwe Schmidt
Prof. Dr. Uwe Schmidt FH Wedel