GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Warum funktioniert der reguläre Ausdruck in X, aber nicht in Y?

Ich habe einen regulären Ausdruck geschrieben, der in einem bestimmten Programm gut funktioniert (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit, …). Aber wenn ich es in einem anderen Programm (oder auf einer anderen Unix-Variante) verwende, passt es nicht mehr. Warum?

Akzeptierte Antwort:

Leider haben verschiedene Tools aus historischen Gründen eine leicht unterschiedliche Syntax für reguläre Ausdrücke, und manchmal haben einige Implementierungen Erweiterungen, die von anderen Tools nicht unterstützt werden. Es gibt zwar Gemeinsamkeiten, aber anscheinend hat jeder Tool-Autor andere Entscheidungen getroffen.

Die Folge davon ist, dass Sie einen regulären Ausdruck, der in einem Tool funktioniert, möglicherweise ändern müssen, damit er in einem anderen Tool funktioniert. Die Hauptunterschiede zwischen gängigen Tools sind:

  • ob die Operatoren +?|(){} erfordert einen umgekehrten Schrägstrich;
  • welche Erweiterungen über die Grundlagen hinaus unterstützt werden .[]*^$ und normalerweise +?|()

In dieser Antwort liste ich die wichtigsten Standards auf. Einzelheiten finden Sie in der Dokumentation der von Ihnen verwendeten Tools.

Der Wikipedia-Vergleich von Engines für reguläre Ausdrücke enthält eine Tabelle, in der die Funktionen aufgeführt sind, die von gängigen Implementierungen unterstützt werden.

Grundlegende reguläre Ausdrücke (BRE)

Grundlegende reguläre Ausdrücke werden durch den POSIX-Standard kodifiziert. Es ist die Syntax, die von grep verwendet wird , sed und vi . Diese Syntax bietet die folgenden Funktionen:

  • ^ und $ passen nur am Anfang und am Ende einer Zeile.
  • . entspricht jedem Zeichen (oder jedem Zeichen außer einem Zeilenumbruch).
  • […] stimmt mit einem der in Klammern aufgeführten Zeichen überein (Zeichensatz). Wenn das erste Zeichen nach der öffnenden Klammer ein ^ ist , werden stattdessen die nicht aufgeführten Zeichen abgeglichen. Um einen ] einzufügen , setzen Sie es direkt nach dem öffnenden [ (oder nach [^ wenn es eine negative Menge ist). Wenn - zwischen zwei Zeichen steht, bezeichnet es einen Bereich; um einen wörtlichen - einzuschließen , platzieren Sie es dort, wo es nicht als Bereich geparst werden kann.
  • Backslash vor einem von ^$.*[ setzt das nächste Zeichen in Anführungszeichen.
  • * stimmt 0, 1 oder öfter mit dem vorhergehenden Zeichen oder Unterausdruck überein.
  • (…) ist eine syntaktische Gruppe zur Verwendung mit * Operator oder Rückverweise und DIGIT Ersatz.
  • Rückverweise 1 , 2 , … stimmen genau mit dem Text überein, der von der entsprechenden Gruppe gefunden wurde, z. (fo*)(ba*)1 entspricht foobaafoo aber nicht foobaafo . Es gibt keine Standardmethode, um sich auf die 10. Gruppe und darüber hinaus zu beziehen (die Standardbedeutung von 10 ist die erste Gruppe gefolgt von einem ).

Die folgenden Funktionen sind ebenfalls Standard, fehlen aber in einigen eingeschränkten Implementierungen:

  • {m,n} stimmt mit dem vorhergehenden Zeichen oder Unterausdruck zwischen m überein zu n mal; n oder m weggelassen werden kann, und {m} bedeutet genau m .
  • In Klammern können Zeichenklassen verwendet werden, zum Beispiel [[:alpha:]] passt zu jedem Buchstaben. Moderne Implementierungen von Klammerausdrücken) enthalten auch Sortierelemente wie [.ll.] und Äquivalenzklassen wie [=a=] .

Das Folgende sind gängige Erweiterungen (insbesondere in GNU-Tools), aber sie sind nicht in allen Implementierungen zu finden. Schlagen Sie im Handbuch des von Ihnen verwendeten Tools nach.

  • | zur Abwechslung:foo|bar entspricht foo oder bar .
  • ? (kurz für {0,1} ) und + (kurz für {1,} ) stimmen höchstens einmal bzw. mindestens einmal mit dem vorhergehenden Zeichen oder Teilausdruck überein.
  • n entspricht einem Zeilenumbruch, t entspricht einem Tab usw.
  • w passt zu jedem Wortbestandteil (kurz für [_[:alnum:]] aber mit Variationen bei der Lokalisierung) und W entspricht jedem Zeichen, das kein Wortbestandteil ist.
  • < und > Übereinstimmung mit der leeren Zeichenfolge nur am Anfang bzw. am Ende eines Wortes; b passt entweder und B stimmt mit b überein nicht.

Beachten Sie, dass Tools ohne | -Operator verfügen nicht über die volle Leistungsfähigkeit regulärer Ausdrücke. Rückverweise ermöglichen einige zusätzliche Dinge, die mit regulären Ausdrücken im mathematischen Sinne nicht möglich sind.

Erweiterte reguläre Ausdrücke (ERE)

Erweiterte reguläre Ausdrücke werden durch den POSIX-Standard kodifiziert. Ihr Hauptvorteil gegenüber BRE ist die Regelmäßigkeit:Alle Standardoperatoren sind reine Satzzeichen, ein umgekehrter Schrägstrich vor einem Satzzeichen steht immer in Anführungszeichen. Es ist die von awk verwendete Syntax , grep -E oder egrep , GNU sed -r , und bashs =~ Operator. Diese Syntax bietet die folgenden Funktionen:

  • ^ und $ passen nur am Anfang und am Ende einer Zeile.
  • . entspricht jedem Zeichen (oder jedem Zeichen außer einem Zeilenumbruch).
  • […] stimmt mit einem der in Klammern aufgeführten Zeichen überein (Zeichensatz). Ergänzung mit einem vorangestellten ^ und Bereiche funktionieren wie in BRE (siehe oben). Zeichenklassen können verwendet werden, fehlen aber bei einigen Implementierungen. Moderne Implementierungen unterstützen auch Äquivalenzklassen und Sortierelemente. Ein umgekehrter Schrägstrich in Klammern zitiert das nächste Zeichen in einigen, aber nicht allen Implementierungen; Verwenden Sie \ um einen umgekehrten Schrägstrich für Portabilität zu bedeuten.
  • (…) ist eine syntaktische Gruppe zur Verwendung mit * oder DIGIT Ersatz.
  • | zur Abwechslung:foo|bar entspricht foo oder bar .
  • * , + und ? stimmt mehrmals mit dem vorhergehenden Zeichen oder Teilausdruck überein:0 oder mehr für * , 1 oder mehr für + , 0 oder 1 für ? .
  • Backslash setzt das nächste Zeichen in Anführungszeichen, wenn es nicht alphanumerisch ist.
  • {m,n} stimmt mit dem vorhergehenden Zeichen oder Unterausdruck zwischen m überein und n Zeiten (fehlen bei einigen Implementierungen); n oder m weggelassen werden kann, und {m} bedeutet genau m .
  • Einige gebräuchliche Erweiterungen wie in BRE:DIGIT Rückverweise (insbesondere fehlen in awk, außer in der busybox-Implementierung, wo Sie $0 ~ "(...)\1" verwenden können ); Sonderzeichen n , t , etc.; Wortgrenzen b und B , Wortbestandteile b und B , …
Verwandte:Meine vorherige Theorie war falsch, also warum funktioniert das?

PCRE (Perl-kompatible reguläre Ausdrücke)

PCRE sind Erweiterungen von ERE, die ursprünglich von Perl eingeführt und von GNU grep -P übernommen wurden und viele moderne Tools und Programmiersprachen , normalerweise über die PCRE-Bibliothek. Siehe die Perl-Dokumentation für nette Formatierungen mit Beispielen. Nicht alle Funktionen der neuesten Version von Perl werden von PCRE unterstützt (z. B. wird die Ausführung von Perl-Code nur in Perl unterstützt). Eine Zusammenfassung der unterstützten Funktionen finden Sie im PCRE-Handbuch. Die wichtigsten Ergänzungen zu ERE sind:

  • (?:…) ist eine nicht einfangende Gruppe:wie (…) , zählt aber nicht für Rückverweise.
  • (?=FOO)BAR (Lookahead) stimmt mit BAR überein , aber nur, wenn es auch eine Übereinstimmung für FOO gibt an der gleichen Position beginnen. Dies ist am nützlichsten, um eine Übereinstimmung zu verankern, ohne den folgenden Text in die Übereinstimmung aufzunehmen:foo(?=bar) entspricht foo aber nur wenn darauf bar folgt .
  • (?!FOO)BAR (negatives Lookahead) stimmt mit BAR überein , aber es gibt auch keine Übereinstimmung für FOO an der gleichen Stelle. Zum Beispiel (?!foo)[a-z]+ entspricht jedem kleingeschriebenen Wort, das nicht mit foo beginnt; [a-z]+(?![0-9) entspricht jedem kleingeschriebenen Wort, dem keine Ziffer folgt (also in foo123 , stimmt es mit fo überein aber nicht foo ).
  • (?<=FOO)BAR (Lookbehind) stimmt mit BAR überein , aber nur, wenn ihm unmittelbar eine Übereinstimmung für FOO vorausgeht . FOO muss eine bekannte Länge haben (Sie können keine Wiederholungsoperatoren wie * verwenden ). Dies ist am nützlichsten, um eine Übereinstimmung zu verankern, ohne den vorangehenden Text in die Übereinstimmung aufzunehmen:(?<=^| )foo entspricht foo aber nur, wenn ihm ein Leerzeichen oder der Anfang der Zeichenfolge vorangestellt ist.
  • (?<!FOO)BAR (negatives Lookbehind) stimmt mit BAR überein , aber nur, wenn ihm nicht unmittelbar eine Übereinstimmung für FOO vorausgeht . FOO muss eine bekannte Länge haben (Sie können keine Wiederholungsoperatoren wie * verwenden ). Dies ist am nützlichsten, um eine Übereinstimmung zu verankern, ohne den vorangehenden Text in die Übereinstimmung aufzunehmen:(?<![a-z])foo entspricht foo aber nur, wenn ihm kein Kleinbuchstabe vorangestellt ist.

Emacs

Die Syntax von Emacs liegt zwischen BRE und ERE. Neben Emacs ist dies die Standard-Syntax für -regex in GNU find. Emacs bietet die folgenden Operatoren:

  • ^ , $ , . , […] , * , + , ? wie in ERE
  • (…) , | , {…} , DIGIT wie in BRE
  • mehr Backslash-Buchstabenfolgen; < und > für Wortgrenzen; und mehr in neueren Versionen von Emacs, die in anderen Engines mit einer Emacs-ähnlichen Syntax oft nicht unterstützt werden.
Verwandte:Verwenden Sie find, um ein bestimmtes Verzeichnis zu finden und alle darin enthaltenen Dateien außer einem Verzeichnis zu löschen?

Muschelkugeln

Shell-Globs (Wildcards) führen einen Mustervergleich mit einer Syntax durch, die sich vollständig von regulären Ausdrücken unterscheidet und weniger leistungsfähig ist. Neben Shells sind diese Wildcards auch mit anderen Tools wie find -name verfügbar und rsync-Filter. POSIX-Muster umfassen die folgenden Merkmale:

  • ? entspricht jedem einzelnen Zeichen.
  • […] ist ein Zeichensatz wie in gängigen Syntaxen für reguläre Ausdrücke. Einige Shells unterstützen keine Zeichenklassen. Einige Shells erfordern ! statt ^ um die Menge zu negieren.
  • * entspricht einer beliebigen Zeichenfolge (häufig außer / beim Abgleich von Dateipfaden; wenn / ist von * ausgeschlossen , dann ** enthält manchmal / , aber sehen Sie in der Dokumentation des Tools nach).
  • Backslash steht für das nächste Zeichen.

Ksh bietet zusätzliche Funktionen, die dem Mustervergleich die volle Leistungsfähigkeit regulärer Ausdrücke verleihen. Diese Funktionen sind auch in Bash verfügbar, nachdem shopt -s extglob ausgeführt wurde . Zsh hat eine andere Syntax, kann aber auch die Syntax von ksh nach setopt ksh_glob unterstützen .


Linux
  1. Warum liefert `md5sum` nicht den gleichen Hash wie das Internet?

  2. Warum enthält die Bash-Übersetzungsdatei nicht alle Fehlertexte?

  3. Linux – Warum funktioniert Setuid nicht?

  4. Linux – Warum funktioniert Locale Es_mx, aber nicht Es?

  5. Die Definition eines regulären Ausdrucks?

Warum funktioniert die Bash-Prozesssubstitution bei einigen Befehlen nicht?

Warum funktioniert `exit &` nicht?

Warum funktioniert Tomcat mit Port 8080, aber nicht mit 80?

Warum funktioniert `\d` nicht in regulären Ausdrücken in sed?

Warum funktioniert diese Regex nicht unter Linux?

Warum funktioniert das Setuid-Bit inkonsistent?