Reguläre Ausdrücke, die „überall“ funktionieren
(johndcook.com)- Reguläre Ausdrücke unterscheiden sich je nach Implementierung in unterstützten Funktionen und Syntax; ein Pattern, das in einem Tool funktioniert, kann in einer anderen Umgebung fehlschlagen oder angepasst werden müssen
- Je vertrauter man mit funktionsreichen Umgebungen wie Perl ist, desto häufiger stößt man auf Kompatibilitätsprobleme; wenn man auch Computer ohne Installationsrechte berücksichtigt, ist es sicherer, eine gemeinsame Teilmenge zu verwenden
- Definiert man „überall“ besonders streng, wird der Umfang so klein, dass im Wesentlichen nur Literale,
[…]-Zeichenklassen und grundlegende Sonderzeichen wie. * ^ $übrig bleiben - Nutzt man GNU
sed,awk,grepsowie die Option-Efürsedundgrep, erweitert sich die nutzbare gemeinsame Funktionsmenge; in dieser Kombination istawkjedoch meist der kleinste gemeinsame Nenner - Emacs benötigt Backslashes vor
+? ( ) { } |, und auch die Bedeutung von\sund\Sunterscheidet sich; wer denselben regulären Ausdruck in mehreren Tools verwenden will, muss daher auch Syntax-Ausnahmen prüfen
Warum Kompatibilität bei regulären Ausdrücken schwierig ist
- Die größte Unbequemlichkeit bei regulären Ausdrücken entsteht durch Unterschiede zwischen Implementierungen
- Eine Funktion, die in einem Tool unterstützt wird, kann in einem anderen Tool komplett fehlen
- Selbst bei derselben Funktion kann sich die Syntax leicht unterscheiden
- Perl ist eine Umgebung für reguläre Ausdrücke mit vielen Funktionen; Features, die aus Perl-Sicht selbstverständlich wirken, können in anderen Umgebungen fehlen
- Man kann zwar Perl-ähnliche Alternativen anderer Tools verwenden, doch das ist nicht standardisiert und erschwert es, Kollegen oder Kunden Code zu schicken, der sofort läuft
- Berücksichtigt man auch Situationen, in denen man auf Computern arbeiten muss, auf denen keine Software installiert werden kann, braucht man einen Ansatz, der eine Teilmenge von Regex-Funktionen findet, die in mehreren Umgebungen funktioniert
- Je strenger man „überall“ definiert, desto weniger Funktionen kann man verwenden
- Literale
[…]-Zeichenklassen- Sonderzeichen
. * ^ $
Gemeinsamer Umfang in sed, awk, grep und Emacs
- Beschränkt man die Ziel-Tools auf
sed,awk,grepund Emacs, kann man den Maßstab für „überall“ etwas lockerer ansetzen - Verwendet man die GNU-Versionen von
sed,awkundgrepund nutzt beisedundgrepdie Option-E, wird die Liste gemeinsamer Funktionen größer- Die Regex-Funktionen der drei Tools sind ähnlich
- Funktionen von
awkwerden in den anderen Tools größtenteils ebenfalls unterstützt - Eine Ausnahme sind Wortgrenzen: In
awkverwendet man\<und\>, was sich von\bund\Bunterscheidet
- Emacs deckt den Großteil der
awk-Funktionen ab, weist aber Syntaxunterschiede auf- Damit
+ ? ( ) { } |dieselbe Rolle wie inawkübernehmen, müssen sie mit einem vorangestellten Backslash geschrieben werden - Die Entsprechungen zu
\sund\Sausawksind in Emacs\s-und\S-
- Damit
- In Emacs stehen
\sund\Snicht für Whitespace/Nicht-Whitespace, sondern leiten eine Zeichenklasse ein- Die Klasse
-bedeutet Whitespace \s.bezeichnet ein Satzzeichen\S.bezeichnet ein Nicht-Satzzeichen
- Die Klasse
- Nach diesem Maßstab können folgende Funktionen verwendet werden
.^,$[…],[^…]*\w,\W,\s,\S- Rückreferenzen von
\1bis\9 \b,\B?,+- Alternative mit
| - Wiederholungsanzahl
{n,m} - Capturing mit
(...)
- Allerdings unterstützt
gawkRückreferenzen in Ersetzungsstrings, nicht jedoch im regulären Ausdruck selbst look-aroundkann man als fortgeschrittene Funktion ansehen, und\dwirkt zwar wie eine grundlegende Funktion für Ziffern, wird aber in vielen Regex-Varianten nicht unterstützt
1 Kommentare
Meinungen auf Hacker News
Bei Emacs fühlt es sich besonders mühsam an, weil man fast raten muss, was escaped werden muss
Es gibt zwar auch eine Alternative namens
rx[0], aber angenehm zu benutzen ist sie in der Praxis nichtÜber die Regex-Syntax selbst hinaus treten auch bei der tatsächlichen Verwendung häufig Probleme mit Encoding und Escaping auf
Gibt man eine Regex in der Shell ein, muss man sie korrekt escapen; in Python muss man etwa prüfen, ob es ein Raw String ist
Trotzdem ist es fast ein modernes Wunder, dass die Art, wie Regexes in den meisten Tools verwendet werden, einigermaßen in einem ähnlichen Rahmen liegt
[0]: https://www.gnu.org/software/emacs/manual/html_node/elisp/Rx...
Dann entstehen ständig Situationen, in denen unterschiedliche Escaping-Regeln ineinander verschachtelt sind
(und)literal matchenDer Autor scheint es fast auszusprechen, aber letztlich wohl sagen zu wollen, dass POSIX Basic Regular Expressions überall funktionieren
Allerdings mit dem Vorbehalt, dass noch nicht alle bei Ausgabe 8 der Single Unix Specification angekommen sind und dass sich BRE in dieser Ausgabe etwas geändert hat
Ohne solche Vorbehalte hätte es gar keinen Grund gegeben, den Artikel überhaupt zu schreiben
Ich habe früher einmal ein Paper über Regexes geschrieben, die sowohl unter greedy Semantics als auch unter leftmost maximal Semantics auf dieselbe Weise matchen
https://par.nsf.gov/servlets/purl/10534654
Ich war schon immer pingelig dabei, klarzustellen, welche Regex-Sprache ein Tool akzeptiert und ob es beliebige Teilstrings, Präfixe, Suffixe, ganze Strings, eine Zeile oder Teilstrings innerhalb einer Zeile matcht
Dazu gehören [die verbreiteteren Varianten][1], außerdem PCRE und Python
Es hat eine Weile gedauert, bis ich gelernt habe, dass einige der älteren Formen, die man etwa bei grep sieht, [in POSIX spezifiziert sind][2]
[1]: https://cppreference.com/cpp/regex#Regular_expression_gramma...
[2]: https://pubs.opengroup.org/onlinepubs/009696899/basedefs/xbd...
Ich möchte Russ Cox’ Regex-Seite teilen
Ich halte sie für gute, lesenswerte Materialien
https://swtch.com/~rsc/regexp/
Aus solchen Gründen ist RFC 9485, I-Regexp: An Interoperable Regular Expression Format, wichtig
https://datatracker.ietf.org/doc/html/rfc9485
Das regexp-Paket der Go-Standardbibliothek unterstützt keine Backreferences, weil es die RE2-Engine verwendet
Bei Ersetzungen kann man sie nutzen, beim Matching aber nicht
regexpverwendet nicht re2, sondern ist eine separate Implementierung derselben KonzepteNachdem ich ähnliche Frustrationen mit Regel-Engines, Template-Engines und IFTTT-artigen Engines erlebt hatte, habe ich eine Rust-Bibliothek für JSONLogic gebaut und nutze auch Bindings für andere Sprachen
https://github.com/GoPlasmatic/datalogic-rs
Auch die JSON-Schema-Dokumentation enthält eine empfohlene Regex-Teilmenge
https://json-schema.org/understanding-json-schema/reference/...