Regular Expressions
als Präsentation ▻Regular Expressions sind eine kleine “Programmiersprache in der Programmiersprache”, eine besondere Schreibweise die es erlaubt in Strings nach Mustern zu suchen und Ersetzungen vorzunehmen.
▻Mit Regular Expressions kann man die Welt retten:
Basierend auf http://xkcd.com/208/ von Randall Munroe - verändert und verwendet unter der CC-BY-NC Lizenz
▻Regular Expressions sind keine Besonderheit von Javascript. und die meisten Programmiersprachen bieten Regular Expressions an. Egal ob Sie also mit vi, grep, mod_rewrite, Javascript, C++ oder Ruby arbeiten, alles was Sie über Regular Expressions lernen zahlt sich aus!
Auch in Kommandozeilne Befehlen (vi, sed) und Editoren gibt es Regular Expressions, z.B. in Visual Studio Code:
Vielleicht kennst Du Regular Expressions also schon? Wie schätzt Du Dich selbst ein? ⭐? 🌧?
▻Reguläre Ausdrücke sind ein Konzept aus der Theoretischen Informatik. Diese ursprünglichen regulären Ausdrücke bieten nur 3 Operatoren an. Bei der praktischen Umsetzung wurden mehr und mehr Operatoren hinzugefügt.
Diese Kapitel beschreibt die praktische Umsetzung, und nicht den Begriff aus der theoretischen Informatik.
▻Regular Expressions nennt man oft auch Muster (en: patterns), man spricht von Mustersuche (en: pattern matching). Wenn ein Muster auf ein Zeichenkette zutrifft sagt man auf Halb-Englisch: “der Pattern matched”.
▻Verwendung von Regular Expressions
In Javascript gibt es viele verschiedene Schreibweise für Regular Expressions,
wir beginnen mit der Methode match
des String-Objekts:
Javascript Code match
var s = "begreifen"; if( s.match(/greif/) ) { console.log("greif gefunden!"); }
Hier wird im String “begreifen” nach dem String “greif” gesucht. Falls er gefunden wird (ja, wird er), gibt die Match-Methoden einen Wert zurück, der als wahr gilt.
▻Für diesen einfachsten Fall wird man aber nicht eine RegEx verwenden,
sondern indexOf
: diese Methode gibt -1 zurück falls der String
nicht gefunden wurde, und die Position der Fundstelle anderfalls.
Javascript Code match
var s = "begreifen"; if( s.indexOf('greif') > -1) { console.log("greif gefunden!"); }
Zeichenkette
Die einfachste Regular Expression besteht aus einer Zeichenkette, nach der “wörtlich” gesucht werden soll. Falls die Zeichenkette irgendwo im String gefunden wird ist die Suche erfolgreich:
/hallo/
Alternative
Mit dem senkrechten Strich |
kann man Alternative definieren, er
entspricht also einem logischen “oder”;
/en|sk|zh|us|uk/
RegEx Tester: /en|sk|zh|us|uk/
▻Verankern
Mit den Zeichen Zirkumflex ^
und Dollar $
kann die Suche am
Anfang bzw. Ende der Strings verankert werden.
/^Am Anfang war/ /dann leben sie noch heute.$/ /^Ganzer String$/
RegEx Tester: /^(en|sk|us|uk)$/
Achtung: der Zirkumflex ^
hat auch noch andere Bedeutungen (wenn er nicht am Anfang des Patterns steht).
Zeichen-Klassen
Wenn für ein Zeichen im String mehrere Zeichen zur Auswahl stehen fasst man sie in einer “Zeichen-Klasse” (en: “character class”) zusammen:
/[aeiou]/
Achtung! Eine Erwähnung der Zeichenklasse matched genau ein Zeichen im String, nicht mehrere Zeichen!
▻Zeichen-Klasse mit Zeichenbereich
Mit einem Bindestrich -
innerhalb der Klasse kann
man einen Bereich von Zeichen angeben, die im Zeichensatz hintereinander
stehen.
Die folgenden beiden pattern sind also gleichbedeutend:
/[abcdef]/ /[a-f]/
Komplement der Zeichen-Klasse
Mit dem Zirkumflex ^
kann man das Komplement der Zeichen-Klasse bilden,
es werden dann alle Zeichen gematched die nicht in der eckigen
Klammer erwähnt werden:
/[^aeiou]/
Achtung: das war die zweite Bedeutung des Zirkumflex ^
, wenn er am Anfang der Klasse steht.
Abkürzungen für häufig benutze Zeichenklassen
/\d/ eine Ziffer, entspricht /[0-9]/ /\D/ keine Ziffer, entspricht /[^0-9]/ /\w/ Wort-Zeichen, entspricht /[a-zA-Z0-9_]/ /\W/ kein Wort-Zeichen, entspricht /[^a-zA-Z0-9_]/
Plus-Operator: mindestens einmal, oder mehrmals
Der Plus-Operator erlaubt eine Wiederholung des vorigen Zeichens. Um also "i"
und "iiii"
und "wir sind die Ritter die ni sagen"
zu matchen:
/i+/
Der Operator kann auch auf Zeichenklassen oder Gruppen angewandt werden.
/\d+/
Wenn man sich den Operator als Schleife vorstellt, kann bei jeder “Wiederholung” ein anderes Zeichen aus der Klasse oder eine andere Alternative gewählt werden:
/(do|re|mi)+/
Übung
Eine kurze Übung in TDDbin: Längenangaben finden
▻Irgend ein Zeichen
Der Punkt .
steht für ein beliebiges Zeichen. Achtung, Verwechslungsgefahr:
bei Pfadangaben hat das Fragezeichen ?
diese Funktion!
/^...$/ genau drei Zeichen
Ein echter Punkt
Da der Punkt .
eine besondere Bedeutung in einer Regular Expression
hat stellt sich die Frage: wie erkennt man dann einen echten Punkt?
Die Antwort: man escaped die Sonderzeichen von RegEx mit einem Backslash \
.
/\./ ein echter punkt
Stern-Operator: beliebig viele
Wir kennen schon den Plus-Operator. Der Stern-Operator erlaubt auch null Wiederholungen.
Der Stern-Operator dient auch der Vervielfältigung: das davor stehende Zeichen kann nullmal, einmal oder mehrmals vorkommen:
/i*/
Fragezeichen-Operator: einmal oder keinmal
Der Frage-Operator erlaubt 0 oder 1 vorkommen des Zeichens.
/\d?/
Gruppieren und Merken
Mit runden Klammern kann man Teile der Regular Expression zusammen fassen:
/(de|fr)_(DE|CH)/
RegEx Tester: /(de|fr)_(DE|CH)/
Ausserdem stehen die von den Klammern gefundenen Teile des
Strings nach der Auswertung zur Verfügung: die Methode match
liefert ein Array als Rückgabewert, an der Stelle 0 ist der
gesamte gefundene String gespeichert, auf 1, 2, 3 der Reihe
nach die gefundnen Gruppen:
locale = "de_CH"; if( match = locale.match(/(de|fr)_(DE|CH)/ ) { console.log("gesamt: " + match[0]); console.log("sprache: " + match[1]); console.log("land: " + match[2]); }
Übung
Eine längere Übung in TDDbin: Längenangaben finden
▻Operatoren sind gierig
Die Operatoren *
und +
versuchen immer
möglichst lange Strings zu erfassen.
/o.*o/ möglichst viele Zeichen zwischen o und o
Diese Eigenschaft sieht man sehr gut in folgendem Beispiel:
▻Wie kann man das gierige Verhalten der Operatoren umgehen?
Die “altmodisch” Methode ist eine Komplement-Klasse:
/o[^o]*o/
Hier wird ein erstes o gematched, dann kommen (null bis viele) zeichen die kein o sind, und dann ein zweites o. Damit ist der Pattern beendet, auch wenn es später im String noch weitere o’s geben würde.
▻In modernen RegEx Engines gibt es nicht-gierige Varianten der Operatoren: ein Fragezeichen wird nachgestellt
/o(.*?)o/ /o(.+?)o/
Mehrmals suchen
Alle bisher geschriebenen Patterns werden mit der Funktion match
einmal gesucht. Wenn ich in einem string aber mehrere Vorkommen
finden will, braucht es das global-Flag:
m = "Nana nana nana nana batman".match(/na/); // findet das erste na m = "Nana nana nana nana batman".match(/na/g); // findet alle 7 nax
Warnhinweis: Was RegEx nicht kann
Mit dem letzten Beispiel könnte man nun in Versuchung kommen verschachtelte Ausdrücke wie HTML, XML, mathematische Ausdrücke, Programmiersprachen mit Hilfe von RegEx zu parsen.
Das funktioniert aber nicht. Das müssten Sie an dieser Stelle einfach mal glauben - den Beweis überlassen wir der “Theoretischen Informatik”.
Die Frage ob das geht kommt immer wieder auf StackOverflow, hier ist die Standard Antwort.
Wenn Sie also in Javascript oder PHP HTML oder XML parsen wollen, dann verwenden Sie dafür einen der vielen fertigen Parser.
Wenn Sie aus einem längeren HTML-Dokument “unverschachtelte” Teile wie
z.B. <img>
Tags herausholen wollen, dann könnsn Sie das mit Regular Expressions machen.
Aber nichts komplizierteres.
Ersetzen mit Regular Expression in Javascript
Ein häufiger Anwendungsfall von RegEx ist “Suchen und Ersetzen”
s = "Voldemort hat keine Nase"; s.replace(/Voldemort/, "Er, dessen Name nicht genannt werden darf,");
Es erfolgt nur eine einzige Ersetzung. Mit dem Modifikator g
am
Ende der RegEx kann man alle Ersetzungen durchführen:
s = "Voldemort hat keine Nase. Voldemort ist verschwunden."; s.replace(/Voldemort/g, "Er, dessen Name nicht genannt werden darf,");
Achtung, auch hier kommt man bald an die Grenzen von Regular Expressions:
s = "Harry greift Voldemort an. Voldemorts Zauberstab bricht."; s.replace(/Voldemort/g, "Er, dessen Name nicht genannt werden darf,");
Dass im zweiten Satz ein anderer Fall notwendig wäre, und wie man das dann richtige formuliert, kann eine Regular Expression nicht erkennen. Dafür gibt es eine eigene Wissenschaft: die Computer-Linguistik beschäftigt sich mit der Analyse, Synthese und Übersetzung von natürlichen Sprachen.
▻RegEx in PHP
Php Code RegEx Beispiel-Code aus Wordpress Plugins
# Beispiel Link Suchen if (preg_match('/^(http)(s?)(:)\/\//',$linky)){ ... # Beispiel Sprache-Code if (preg_match ( "/en|sk|zh|us|uk/", \$locale_code )){ ...
Php Code Suchen mit RegEx in PHP
preg_match( "/regex/i", "string in dem ich suche")
Tools
- regexr.com ein CodePen für Regular Expressions
Vertiefung
- Video: Lea Verou Demystifying Regular Expressions
- Regular Expressions Guide auf MDN
- Wikipedia: Regular Expression