Skriptsprachen: Python
Regular Expressions
Jan Krüger, Alexander Sczyrba
Technische Fakultät Universität Bielefeld
12. Februar 2018
Reguläre Ausdrücke
Was wir machen wollen OHNE irgendeinen Texteditor zu verwenden (STRG+Fist keine Textsuche):
• Text-Dateien zeilenweise einlesen
• Zeilen nach Mustern durchsuchen
• Zeilen in Teilworte zerlegen
• Textstücke ersetzen
Reguläre Ausdrücke
Was wir machen wollen OHNE irgendeinen Texteditor zu verwenden (STRG+Fist keine Textsuche):
• Text-Dateien zeilenweise einlesen
• Zeilen nach Mustern durchsuchen
• Zeilen in Teilworte zerlegen
• Textstücke ersetzen
Reguläre Ausdrücke
Was wir machen wollen OHNE irgendeinen Texteditor zu verwenden (STRG+Fist keine Textsuche):
• Text-Dateien zeilenweise einlesen
• Zeilen nach Mustern durchsuchen
• Zeilen in Teilworte zerlegen
• Textstücke ersetzen
Reguläre Ausdrücke
Was wir machen wollen OHNE irgendeinen Texteditor zu verwenden (STRG+Fist keine Textsuche):
• Text-Dateien zeilenweise einlesen
• Zeilen nach Mustern durchsuchen
• Zeilen in Teilworte zerlegen
• Textstücke ersetzen
Reguläre Ausdrücke
• Beschreiben einfache Sprachen
• „schwächste“ Chomsky-Grammatik
• In Python: Regular Expressions (RE), nach Perl-Syntax
• Regular Expressions in Python deutlich mächtiger als Reguläre Sprachen
Reguläre Ausdrücke
Wir arbeiten mit demre-Modul, dass uns die Funktionalität von Perl-RE zur Verfügung stellt.
In Python geht alles von einempattern-Objekt aus, das entsprechende Funktionen anbietet.
> i m p o r t re
> s t o r y = ’ In ␣ a ␣ h o l e ␣ in ␣ the ␣ g r o u n d ␣ t h e r e ␣ l i v e d ␣ a ␣ b o g g i t . ’
> p = re . c o m p i l e ( r " in " )
> m = p . m a t c h ( s t o r y ) # S u c h t am S t r i n g a n f a n g
> m # K e i n T r e f f e r - > N o n e
> m = p . s e a r c h ( s t o r y ) # S u c h t im g e s a m t e n S t r i n g
> m # Match - O b j e k t
< _ s r e . S R E _ M a t c h at 0 x 1 0 4 2 a 9 6 4 8 >
Pattern-Objekt
Das Pattern wird mit derre.compile(<RE_STR>, <FLAGS>)erstellt.
• Das Pattern beginnt mit einem vorangestelltenr gefolgt von der eigentlichen RE als String (Bsp: re.compile(r"[a-Z]*"))
• Häufigst verwendeterModifier (Flag):
re.IGNORECASE Ignoriere Groß- und Kleinschreibung Aus dem obigen Beispiel folgt:
re.compile(r"[a-z]*", re.IGNORECASE)
Match-Objekt
Auf demmatch-Objekt sind folgende Methoden definiert:
group() Rückgabewert: Der gematchte String start() Rückgabewert: Startindex des Matches
end() Rückgabewert: Endindex des Matches span() Rückgabewert: Start-/Endindex als Tupel
Match-Objekt
Wenn ein Treffer gefunden wurde, so wird ein match-Objekt zurückgeliefert, ansonstenNone.
Generelles Vorgehen zur RE-Verarbeitung in Python
> p = re . c o m p i l e ( < PATTERN >)
> m = p . m a t c h ( ’ s t r i n g ␣ g o e s ␣ h e r e ’ )
> if m :
> p r i n t ’ M a t c h ␣ f o u n d : ␣ ’ , m . g r o u p () , ’ ␣ w i t h ␣ i n d i c e s ␣ ’ , m . s p a n ()
> e l s e :
> p r i n t ’ No ␣ m a t c h ’
Pattern – findall() & finditer()
Um alle Vorkommen zu finden, verwendetfindall() bzw.
finditer():
> p = re . c o m p i l e ( ’ \ d + ’ )
> p . f i n d a l l ( ’ 12 ␣ d r u m m e r s ␣ d r u m m i n g , ␣ 11 ␣ p i p e r s ␣ piping ,
␣ ␣ 10 ␣ l o r d s ␣ a - l e a p i n g ’ )
[ ’ 12 ’ , ’ 11 ’ , ’ 10 ’ ] # A l l e g e f u n d e n e n M a t c h e s als L i s t e
> i t e r a t o r = p . f i n d i t e r ( ’ 12 ␣ d r u m m e r s ␣ d r u m m i n g , ␣ 11 ␣ ... ␣ 10 ␣ ... ’ )
> i t e r a t o r # I t e r a t o r mit match - O b j e k t e n
< c a l l a b l e - i t e r a t o r o b j e c t at 0 x ... >
> for m a t c h in i t e r a t o r :
> p r i n t m a t c h . s p a n () (0 , 2)
(22 , 24) (29 , 31)
sub() – Patternersetzung
Mitsub(<REPL>, <STR>[, count=0]) (Substitute) können Pattern mitREPLersetzt werden. Die maximale Ersetzungshäufigkeit kann mit countangegeben werden.
> t = ’ 12 ␣ d r u m m e r s ␣ d r u m m i n g , ␣ 11 ␣ p i p e r s ␣ piping , . . . ’
> p = re . c o m p i l e ( ’ umm ’ )
> p . sub ( " ift " , t )
’ 12 ␣ d r i f t e r s ␣ d r i f t i n g , ␣ 11 ␣ p i p e r s ␣ piping , . . . ’
> p . sub ( " r i f t " , t , c o u n t =1)
’ 12 ␣ d r i f t e r s ␣ d r u m m i n g , ␣ 11 ␣ p i p e r s ␣ piping , . . . ’
Übung – Suchen und Ersetzen
Die nachfolgend genannten Textdateien findet ihr in
/vol/lehre/python/. Es handelt sich um Theaterstücke von Wayne Anthoney.
• Wieviele Zeilen von romeo.txtenthalten das Wort „Gold“?
• Gib die jeweiligen Indexpositionen der Treffer pro Zeile aus.
• Ersetze in dem Texteric.txtdas Wort „Estragon“ durch „Basil“ und
„Vladimir“ durch „Ilych“.
RegEx
• Alternativen:r"Huey|Dewey|Louie"
• Gruppierung: r"(Hu|Dew)ey|Louie"
• Quantoren
r " ab ? a " # aa , aba
r " ab * a " # aa , aba , abba , abbba , abbbba , ...
r " ab + a " # aba , abba , abbba , abbbba , ...
r " ab {3 ,6} a " # abbba , abbbba , abbbbba , a b b b b b b a r " a ( bab )+ a " # ababa , ababbaba , a b a b b a b b a b a , ...
RegEx
• Zeichenklassen
r " h e l l o \ s + w o r l d " # w h i t e s p a c e r " es ␣ ist ␣ \ d + ␣ Uhr " # d i g i t s r " name : ␣ \ w + " # l e t t e r s ( w o r d s )
• „Gegenteile“: \S, \D, \W
• Selbst erstellte Zeichenklasse
r " M [ ea ][ iy ] er " # Meier , Meyer , Maier , M a y e r r " [ a - z ]{2 ,8} " # Account - N a m e n
r " [ A - Z ][^0 -9]+ "
• Passt auf alles: .
Anker
Muster an bestimmte Position binden:
• Zeilenanfang/-ende
r " ^ L O C U S .+ " # L O C U S Z e i l e aus G e n B a n k D a t e i r " \ s + $ " # all t r a i l i n g w h i t e s p a c e
r " ^\ d + ␣ \ d + ␣ \ d + $ " # 3 d c o o r d
• Wortzwischenraum
r " \ bmit \ b " # " n i c h t mit mir " , " K o m m e n Sie mit !"
r " \ bmit \ B " # " m i t t e n d r i n " , n i c h t " v e r m i t t e l n "
Übung – Zeilen extrahieren
• Lies die Datei/etc/serviceszeilenweise ein.
◦ Gib alle Zeilen aus, die sich auf das ProtokollTCPbeziehen.
◦ Gib alle Zeilen aus, die einen Service deviieren (also keine Kommentarzeile sind).
◦ Gib alle Zeilen aus, die eine vier- oder fünfstellige Port-Nummer enthalten.
• Wie können alle Zeilen aus romeo.txtextrahiert werden, in denen die Worte „club“ oder „clubs“ vorkommen, aber nicht „clubroom“?
Pattern Capturing
• Bis jetzt: Muster kommen im Text vor!
• Aber: Wie sah der Treffer aus?→ findall nur halbe Wahrheit
• Interessanten Bereich markieren:
r " ^ L O C U S \ s +(\ S +) "
r " ^ V E R S I O N \ s +(\ S + ) \ . ( \ d +)\ s + GI :(\ d +) $ "
• Treffer landen bei match immatch-Objekt
> p = re . c o m p i l e ( r ’ a ( b (( c ) d )) ’ )
> m = p . m a t c h ( ’ a b c d ’ )
> m . g r o u p () # G e s a m t e r M a t c h - > m . g r o u p (0)
’ a b c d ’
> m . g r o u p s () # M a r k i e r t e G r u p p e n ( ’ bcd ’ , ’ cd ’ , ’ c ’ )
> m . g r o u p (2)
’ cd ’
• Quantoren richtig einsetzen:(\w)+ !=(\w+)
Pattern Capturing
• Bis jetzt: Muster kommen im Text vor!
• Aber: Wie sah der Treffer aus?→ findall nur halbe Wahrheit
• Interessanten Bereich markieren:
r " ^ L O C U S \ s +(\ S +) "
r " ^ V E R S I O N \ s +(\ S + ) \ . ( \ d +)\ s + GI :(\ d +) $ "
• Treffer landen bei match immatch-Objekt
> p = re . c o m p i l e ( r ’ a ( b (( c ) d )) ’ )
> m = p . m a t c h ( ’ a b c d ’ )
> m . g r o u p () # G e s a m t e r M a t c h - > m . g r o u p (0)
’ a b c d ’
> m . g r o u p s () # M a r k i e r t e G r u p p e n ( ’ bcd ’ , ’ cd ’ , ’ c ’ )
> m . g r o u p (2)
’ cd ’
• Quantoren richtig einsetzen:(\w)+ !=(\w+)
Pattern Capturing
• Bis jetzt: Muster kommen im Text vor!
• Aber: Wie sah der Treffer aus?→ findall nur halbe Wahrheit
• Interessanten Bereich markieren:
r " ^ L O C U S \ s +(\ S +) "
r " ^ V E R S I O N \ s +(\ S + ) \ . ( \ d +)\ s + GI :(\ d +) $ "
• Treffer landen bei match immatch-Objekt
> p = re . c o m p i l e ( r ’ a ( b (( c ) d )) ’ )
> m = p . m a t c h ( ’ a b c d ’ )
> m . g r o u p () # G e s a m t e r M a t c h - > m . g r o u p (0)
’ a b c d ’
> m . g r o u p s () # M a r k i e r t e G r u p p e n ( ’ bcd ’ , ’ cd ’ , ’ c ’ )
> m . g r o u p (2)
’ cd ’
• Quantoren richtig einsetzen:(\w)+ !=(\w+)
Pattern Capturing
• Bis jetzt: Muster kommen im Text vor!
• Aber: Wie sah der Treffer aus?→ findall nur halbe Wahrheit
• Interessanten Bereich markieren:
r " ^ L O C U S \ s +(\ S +) "
r " ^ V E R S I O N \ s +(\ S + ) \ . ( \ d +)\ s + GI :(\ d +) $ "
• Treffer landen bei match immatch-Objekt
> p = re . c o m p i l e ( r ’ a ( b (( c ) d )) ’ )
> m = p . m a t c h ( ’ a b c d ’ )
> m . g r o u p () # G e s a m t e r M a t c h - > m . g r o u p (0)
’ a b c d ’
> m . g r o u p s () # M a r k i e r t e G r u p p e n ( ’ bcd ’ , ’ cd ’ , ’ c ’ )
> m . g r o u p (2)
’ cd ’
• Quantoren richtig einsetzen:(\w)+ !=(\w+)
Pattern Capturing
• Bis jetzt: Muster kommen im Text vor!
• Aber: Wie sah der Treffer aus?→ findall nur halbe Wahrheit
• Interessanten Bereich markieren:
r " ^ L O C U S \ s +(\ S +) "
r " ^ V E R S I O N \ s +(\ S + ) \ . ( \ d +)\ s + GI :(\ d +) $ "
• Treffer landen bei match immatch-Objekt
> p = re . c o m p i l e ( r ’ a ( b (( c ) d )) ’ )
> m = p . m a t c h ( ’ a b c d ’ )
> m . g r o u p () # G e s a m t e r M a t c h - > m . g r o u p (0)
’ a b c d ’
> m . g r o u p s () # M a r k i e r t e G r u p p e n ( ’ bcd ’ , ’ cd ’ , ’ c ’ )
> m . g r o u p (2)
Übung – Romeo, oh Romeo...
Inromeo.txtfindet sich die Regieanweisung der „ROMEO enters“.
Extrahiert die Namen der Personen, die auf diese Weise die Bühne betreten. Verwendet einen geeigneten Datentyp, um die Personen lediglich einmalig zu speichern.
Pattern Capturing
• Das Muster muss vollständig passen:
> p = re . c o m p i l e ( r ’ a ( b (( c ) d )) ’ )
> m = p . m a t c h ( ’ abcd ’ )
> type ( m ) N o n e T y p e
• Unterschied zwischen groupingundcapturing:
r " \ d +( -\ d +)* " # -12345 r " \ d +(?: -\ d +)* " # 1 2 3 4 5
Übung – Servicelist as a Service
Lies/etc/servicesein. Stelle die Informationen über die Dienste etwas umgangssprachlicher dar.
Für die Zeile ftp 21/tcpsoll die Ausgabe wie folgt aussehen:
Der Dienst "ftp"verwendet TCP auf Port 21
Eventuelle weitere Informationen (Alias-Name oder Kommentare) sollen ignoriert werden.
Greedy Matches
• Was passiert, wenn Pattern nicht eindeutig sind?
> t = " a a a a a a a a a a "
> p = re . c o m p i l e ( r " ( a +)( a +) " )
> m = p . m a t c h ( t )
> m . g r o u p () # ???
> m . g r o u p s () # ???
• Ausprobieren: r " ( a +)( a *) " r " ( a *)( a +) " r " ( a *)( a *) " r " ( a ?)( a *) " r " ( a {2 ,4})( a *) "
• Setze hinter den ersten Quantoren: +? *? ?? {2,4}?
Greedy Matches
• Was passiert, wenn Pattern nicht eindeutig sind?
> t = " a a a a a a a a a a "
> p = re . c o m p i l e ( r " ( a +)( a +) " )
> m = p . m a t c h ( t )
> m . g r o u p () # ???
> m . g r o u p s () # ???
• Ausprobieren:
r " ( a +)( a *) "
r " ( a *)( a +) "
r " ( a *)( a *) "
r " ( a ?)( a *) "
r " ( a {2 ,4})( a *) "
• Setze hinter den ersten Quantoren: +? *? ?? {2,4}?
Greedy Matches
• Was passiert, wenn Pattern nicht eindeutig sind?
> t = " a a a a a a a a a a "
> p = re . c o m p i l e ( r " ( a +)( a +) " )
> m = p . m a t c h ( t )
> m . g r o u p () # ???
> m . g r o u p s () # ???
• Ausprobieren:
r " ( a +)( a *) "
r " ( a *)( a +) "
r " ( a *)( a *) "
r " ( a ?)( a *) "
Text zerteilen
• Sequenzkomponenten zu einen String vereinen:
> l = [ ’ b ’ , 1 , ’ f f e e g ’ ]
> " " . j o i n ( map ( str , l ))
’ b 1 f f e e g ’
• Entgegengesetzte Funktion mit RE: split(string[, count=0])
• Trennung durch Pattern:
> s t o r y = " In ␣ a ␣ h o l e ␣ in ␣ the ␣ g r o u n d ␣ t h e r e ␣ l i v e d ␣ a ␣ h o b b i t . "
> p = re . c o m p i l e ( r " \ s " )
> p . s p l i t ( s t o r y )
[ ’ In ’ , ’ a ’ , ’ h o l e ’ , ’ in ’ , ’ the ’ , ’ g r o u n d ’ , ’ t h e r e ’ , ’ l i v e d ’ ,
’ a ’ , ’ h o b b i t . ’ ]
Übung – Sätzlein, trenn dich!
Trenne den Satz
„In a hole in the ground there lived a hobbit.“
mit den folgenden Mustern. Welche Worte entstehen dabei?
r " ␣ "
r " "
r " \ s * "
r " \ b "
r " \ B "