431 Stimmen

Regulärer Ausdruck für die Übereinstimmung von ausgeglichenen Klammern

Ich brauche einen regulären Ausdruck, um den gesamten Text zwischen zwei äußeren Klammern auszuwählen.

Exemple :
START_TEXT(text here(possible text)text(possible text(more text)))END_TXT
^ ^

Ergebnis:
(text here(possible text)text(possible text(more text)))

7 Stimmen

Diese Frage ist sehr schlecht, weil nicht klar ist, worum es geht. Alle Antworten haben sie unterschiedlich interpretiert. @DaveF können Sie bitte die Frage klären?

2 Stimmen

In diesem Beitrag wird geantwortet: stackoverflow.com/questions/6331065/

275voto

bobble bubble Punkte 11439

Ich möchte diese Antwort zum schnellen Nachschlagen hinzufügen. Sie können sie gerne aktualisieren.


.NET Regex mit Bilanzkreise .

\((?>\((?<c>)|[^()]+|\)(?<-c>))*(?(c)(?!))\)

Wo c wird als Tiefenzähler verwendet.

[Demo auf Regexstorm.com](http://regexstorm.net/tester?p=%5C((%3F%3E%5C((%3F%3Cc%3E)%7C%5B%5E()%5D%2B%7C%5C)(%3F%3C-c%3E))*(%3F(c)(%3F!))%5C)&i=some%20text(text%20here(possible%20text)text(possible%20text(more%20text)))end%20text)


PCRE unter Verwendung einer rekursives Muster .

\((?:[^)(]+|(?R))*+\)

Demo bei regex101 Oder ohne Abwechslung:

\((?:[^)(]*(?R)?)*+\)

Demo bei regex101 ; Oder abgerollt für Leistung:

\([^)(]*+(?:(?R)[^)(]*)*+\)

Demo bei regex101 Das Muster ist eingefügt bei (?R) die die (?0) .

Perl, PHP, Notepad++, R : perl=TRUE , Python : Regex-Paket con (?V1) für das Perl-Verhalten.


Rubinrot mit Aufruf von Unterausdrücken .

Mit Ruby 2.0 \g<0> kann verwendet werden, um ein vollständiges Muster aufzurufen.

\((?>[^)(]+|\g<0>)*\)

Demo bei Rubular Ruby 1.9 unterstützt nur Erfassung der Gruppenrekursion :

(\((?>[^)(]+|\g<1>)*\))

Demo bei Rubular  ( atomare Gruppierung seit Ruby 1.9.3)


JavaScript   API :: XRegExp.matchRecursive

XRegExp.matchRecursive(str, '\\(', '\\)', 'g');

JS, Java und andere Regex-Varianten ohne Rekursion bis zu 2 Verschachtelungsebenen:

\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)

Demo bei regex101 . Tiefer Verschachtelung muss hinzugefügt werden zum Muster.
Schnelleres Scheitern bei unausgeglichener Klammerung die + Quantifizierer.


Java : Eine interessante Idee mit Vorwärtsreferenzen von @jaytea .


<a href="https://stackoverflow.com/a/22944075/5527985">Referenz - Was bedeutet diese Regex?</a>

1 Stimmen

Wenn Sie eine Gruppe mit einem Possessivquantor wiederholen, ist es sinnlos, diese Gruppe atomar zu machen, da alle Rückverfolgungspositionen in dieser Gruppe bei jeder Wiederholung gelöscht werden. Schreiben Sie also (?>[^)(]+|(?R))*+ ist dasselbe wie das Schreiben (?:[^)(]+|(?R))*+ . Dasselbe gilt für das nächste Muster. Bei der ausgerollten Version können Sie hier einen Possessivquantor setzen: [^)(]*+ um einen Rücksprung zu verhindern (falls keine schließende Klammer vorhanden ist).

0 Stimmen

Über das Ruby 1.9-Muster, anstatt die wiederholte Gruppe atomar zu machen (das hat ein begrenztes Interesse, wenn es viele verschachtelte Klammern gibt (...(..)..(..)..(..)..(..)..) ) in der Betreff-Zeichenkette), können Sie eine einfache nicht-einfangende Gruppe verwenden und alles in eine atomare Gruppe einschließen: (?>(?:[^)(]+|\g<1>)*) (dies verhält sich genau wie ein Possessivquantor). In Ruby 2.x ist der possessive Quantifizierer verfügbar.

1 Stimmen

@CasimiretHippolyte Vielen Dank! Ich habe die PCRE-Muster angepasst und für Ruby 1.9, meinen Sie das ganze Muster zu sein wie diese ? Bitte aktualisieren Sie sich selbst. Ich verstehe, was Sie meinen, bin mir aber nicht sicher, ob es eine große Verbesserung gibt.

181voto

Frank Punkte 60769

Reguläre Ausdrücke sind das falsche Werkzeug für diese Aufgabe, da es sich um verschachtelte Strukturen handelt, d. h. um Rekursion.

Dafür gibt es einen einfachen Algorithmus, den ich ausführlicher beschrieben habe in dieser Antwort を、その vorherige Frage . Im Wesentlichen geht es darum, einen Code zu schreiben, der die Zeichenkette durchsucht und einen Zähler für die offenen Klammern führt, die noch nicht durch eine schließende Klammer ergänzt wurden. Wenn dieser Zähler auf Null zurückgeht, dann wissen Sie, dass Sie die letzte schließende Klammer erreicht haben.

0 Stimmen

Ich habe mit dieser Idee gespielt, aber ich dachte, dass ich es vielleicht mit RegExp machen kann. Ich werde zu meinem ursprünglichen Plan zurückkehren. Vielen Dank an alle

24 Stimmen

Die .NET-Implementierung hat [Balancing Group Definitions msdn.microsoft.com/de-us/library/ die diese Art von Dingen erlauben.

49 Stimmen

Ich bin nicht der Meinung, dass reguläre Ausdrücke dafür das falsche Werkzeug sind, und zwar aus mehreren Gründen. 1) Die meisten Implementierungen regulärer Ausdrücke haben eine praktikable, wenn auch nicht perfekte Lösung für diese Aufgabe. 2) Oft versucht man, ausgewogene Paare von Begrenzungszeichen in einem Kontext zu finden, in dem auch andere Kriterien, die sich gut für reguläre Ausdrücke eignen, eine Rolle spielen. 3) Oft gibt man einen regulären Ausdruck in eine API ein, die nur reguläre Ausdrücke akzeptiert, und man hat keine andere Wahl.

144voto

rogal111 Punkte 5794

Sie können verwenden Regex-Rekursion :

\(([^()]|(?R))*\)

5 Stimmen

Ein Beispiel wäre hier wirklich nützlich, ich kann das nicht für Dinge wie "(1, (2, 3)) (4, 5)" hinbekommen.

5 Stimmen

@AndyHayden das liegt daran, dass "(1, (2, 3)) (4, 5)" zwei durch Leerzeichen getrennte Gruppen hat. Verwenden Sie meine Regexp mit globalem Flag: /(([^()]|(?R))*)/g. Hier ist ein Online-Test: regex101.com/r/lF0fI1/1

1 Stimmen

Ich habe letzte Woche eine Frage zu diesem Thema gestellt stackoverflow.com/questions/26385984/rekursive-muster-in-regex

34voto

Zach Scrivena Punkte 28381
[^\(]*(\(.*\))[^\)]*

[^\(]* passt auf alles, was keine öffnende Klammer am Anfang der Zeichenfolge ist, (\(.*\)) erfasst die gewünschte Teilzeichenkette, die in Klammern eingeschlossen ist, und [^\)]* passt auf alles, was keine schließende Klammer am Ende der Zeichenkette ist. Beachten Sie, dass dieser Ausdruck nicht versucht, Klammern abzugleichen; ein einfacher Parser (siehe Antwort von dehmann ) wäre dafür besser geeignet.

0 Stimmen

Die Klammer innerhalb der Klasse muss nicht escaped werden. Da sie innerhalb der Klasse nicht metacharakteristisch ist.

16 Stimmen

Dieser Ausdruck scheitert bei einer Eingabe wie "text(text)text(text)text" und liefert "(text)text(text)". Reguläre Ausdrücke können keine Klammern zählen.

27voto

Somnath Musib Punkte 3158

Diese Antwort erklärt die theoretische Einschränkung, warum reguläre Ausdrücke nicht das richtige Werkzeug für diese Aufgabe sind.


Reguläre Ausdrücke können dies nicht tun.

Reguläre Ausdrücke basieren auf einem Berechnungsmodell, das als Finite State Automata (FSA) . Wie der Name schon sagt, ist ein FSA kann sich nur an den aktuellen Zustand erinnern, er hat keine Informationen über die vorherigen Zustände.

FSA

In dem obigen Diagramm sind S1 und S2 zwei Zustände, wobei S1 der Anfangs- und Endschritt ist. Wenn wir also mit der Zeichenfolge 0110 verläuft der Übergang wie folgt:

      0     1     1     0
-> S1 -> S2 -> S2 -> S2 ->S1

In den oben genannten Schritten, wenn wir bei der zweiten S2 d.h. nach dem Parsen 01 de 0110 hat die FSA keine Informationen über den früheren 0 en 01 da es sich nur den aktuellen Zustand und das nächste Eingabesymbol merken kann.

In der obigen Aufgabe müssen wir die Anzahl der öffnenden Klammern kennen, d.h. sie muss sein gespeichert an einem bestimmten Ort. Aber da FSAs kann das nicht, ein regulärer Ausdruck kann nicht geschrieben werden.

Es kann jedoch ein Algorithmus geschrieben werden, der diese Aufgabe übernimmt. Algorithmen fallen im Allgemeinen unter Pushdown Automata (PDA) . PDA ist eine Ebene über FSA . PDA hat einen zusätzlichen Stapel, um einige zusätzliche Informationen zu speichern. PDAs können verwendet werden, um das oben genannte Problem zu lösen, denn wir können ' push ' die öffnende Klammer im Stapel und ' pop ', sobald wir auf eine schließende Klammer stoßen. Wenn der Stapel am Ende leer ist, dann stimmen öffnende und schließende Klammer überein. Andernfalls nicht.

0 Stimmen

4 Stimmen

Hier gibt es mehrere Antworten, die beweisen, dass es möglich ist.

6 Stimmen

@Marco In dieser Antwort geht es um reguläre Ausdrücke in theoretischer Hinsicht. Viele Regex-Engines verlassen sich heutzutage nicht nur auf dieses theoretische Modell und verwenden zusätzlichen Speicher, um die Arbeit zu erledigen!

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X