Ich benötige einen regulären Ausdruck, um den gesamten Text zwischen zwei äußeren Klammern auszuwählen.
Beispiel: some text(text here(possible text)text(possible text(more text)))end text
Ergebnis: (text here(possible text)text(possible text(more text)))
Antworten:
Reguläre Ausdrücke sind das falsche Werkzeug für den Job, da es sich um verschachtelte Strukturen handelt, dh um Rekursion.
Dafür gibt es jedoch einen einfachen Algorithmus, den ich in dieser Antwort auf eine vorherige Frage beschrieben habe .
quelle
Ich möchte diese Antwort zur schnellen Referenz hinzufügen. Fühlen Sie sich frei zu aktualisieren.
.NET Regex mit Ausgleichsgruppen .
Wo
c
wird als Tiefenzähler verwendet.Demo bei Regexstorm.com
PCRE unter Verwendung eines rekursiven Musters .
Demo bei regex101 ; Oder ohne Abwechslung:
Demo bei regex101 ; Oder für die Leistung abgerollt :
Demo bei regex101 ; Das Muster wird eingefügt, bei
(?R)
dem dargestellt wird(?0)
.Perl, PHP, Notepad ++, R : Perl = TRUE , Python : Regex-Paket mit
(?V1)
für Perl-Verhalten.Ruby verwendet Unterausdrucksaufrufe .
Mit Ruby 2.0
\g<0>
kann das vollständige Muster aufgerufen werden.Demo bei Rubular ; Ruby 1.9 unterstützt nur die Erfassung der Gruppenrekursion :
Demo bei Rubular ( Atomgruppierung seit Ruby 1.9.3)
JavaScript API :: XRegExp.matchRecursive
JS-, Java- und andere Regex-Varianten ohne Rekursion bis zu 2 Verschachtelungsebenen:
Demo bei regex101 . Dem Muster muss eine tiefere Verschachtelung hinzugefügt werden .
Um bei unausgeglichenen Klammern schneller zu versagen, lassen Sie den
+
Quantifizierer fallen.Java : Eine interessante Idee mit Forward-Referenzen von @jaytea .
Referenz - Was bedeutet dieser Regex?
quelle
(?>[^)(]+|(?R))*+
ist also dasselbe wie Schreiben(?:[^)(]+|(?R))*+
. Gleiches gilt für das nächste Muster.[^)(]*+
In Bezug auf die entrollte Version können Sie hier einen Possessivquantifizierer einfügen: um ein Zurückverfolgen zu verhindern (falls es keine schließende Klammer gibt).(...(..)..(..)..(..)..(..)..)
), eine einfache nicht erfassende Gruppe verwenden und alle in eine atomare Gruppe einschließen:(?>(?:[^)(]+|\g<1>)*)
( Dies verhält sich genau wie ein Possessivquantifizierer. In Ruby 2.x ist der Possessivquantifizierer verfügbar.Sie können die Regex-Rekursion verwenden :
quelle
Unrecognized grouping construct
.[^\(]*
Entspricht allem, was keine öffnende Klammer am Anfang der Zeichenfolge ist,(\(.*\))
erfasst die erforderliche Teilzeichenfolge in Klammern und[^\)]*
stimmt mit allem überein, was keine schließende Klammer am Ende der Zeichenfolge ist. Beachten Sie, dass dieser Ausdruck nicht versucht, mit Klammern übereinzustimmen. Ein einfacher Parser (siehe Dehmanns Antwort ) wäre dafür besser geeignet.quelle
Wenn Sie Text zwischen zwei übereinstimmenden Klammern auswählen möchten , haben Sie mit regulären Ausdrücken kein Glück. Dies ist unmöglich (*) .
Diese Regex gibt nur den Text zwischen der ersten öffnenden und der letzten schließenden Klammer in Ihrer Zeichenfolge zurück.
(*) Es sei denn, Ihre Regex-Engine verfügt über Funktionen wie Ausgleichsgruppen oder Rekursion . Die Anzahl der Motoren, die solche Funktionen unterstützen, wächst langsam, ist aber immer noch nicht allgemein verfügbar.
quelle
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.
Reguläre Ausdrücke basieren auf einem Rechenmodell, das als bekannt ist
Finite State Automata (FSA)
. Wie der Name schon sagt,FSA
kann sich a nur an den aktuellen Status erinnern, es enthält keine Informationen zu den vorherigen Status.Im obigen Diagramm sind S1 und S2 zwei Zustände, in denen S1 der Start- und Endschritt ist. Wenn wir es also mit der Zeichenfolge versuchen, läuft
0110
der Übergang wie folgt ab:In den obigen Schritten hat die FSA , wenn wir uns auf dem zweiten Platz befinden,
S2
dh nach dem Parsen01
von0110
, keine Informationen über den vorherigen0
in,01
da sie sich nur an den aktuellen Status und das nächste Eingabesymbol erinnern kann.In dem obigen Problem müssen wir die Anzahl der öffnenden Klammern kennen; Dies bedeutet , es muss gespeichert an einem Ort. Da dies
FSAs
aber nicht möglich ist, kann kein regulärer Ausdruck geschrieben werden.Für diese Aufgabe kann jedoch ein Algorithmus geschrieben werden. Algorithmen fallen in der Regel unter
Pushdown Automata (PDA)
.PDA
ist eine Ebene überFSA
. Der PDA verfügt über einen zusätzlichen Stapel zum Speichern einiger zusätzlicher Informationen. PDAs können verwendet werden, um das obige Problem zu lösen, da wirpush
die öffnende Klammer im Stapel undpop
sie öffnen können, sobald wir auf eine schließende Klammer stoßen. Wenn der Stapel am Ende leer ist, stimmen das Öffnen der Klammer und das Schließen der Klammer überein. Sonst nicht.quelle
Es ist tatsächlich möglich, dies mit regulären .NET-Ausdrücken zu tun, aber es ist nicht trivial. Lesen Sie es daher sorgfältig durch.
Sie können einen schönen Artikel lesen Sie hier . Möglicherweise müssen Sie auch reguläre .NET-Ausdrücke nachlesen. Sie können anfangen zu lesen hier .
Winkelklammern
<>
wurden verwendet, da sie kein Entweichen erfordern.Der reguläre Ausdruck sieht folgendermaßen aus:
quelle
Dies ist der endgültige Regex:
Beispiel:
Beachten Sie, dass die
'(pip'
Zeichenfolge korrekt verwaltet wird. (versucht in Regulierungsbehörde: http://sourceforge.net/projects/regulator/ )quelle
Ich habe eine kleine JavaScript-Bibliothek namens Balanced geschrieben , um bei dieser Aufgabe zu helfen. Sie können dies erreichen, indem Sie dies tun
Sie können sogar ersetzen:
Hier ist ein komplexeres und interaktiveres Beispiel für JSFiddle .
quelle
Zusätzlich zur Antwort von Bobble Bubble gibt es andere Regex-Varianten, bei denen rekursive Konstrukte unterstützt werden.
Lua
Verwendung
%b()
(%b{}
/%b[]
für geschweifte Klammern / eckige Klammern):for s in string.gmatch("Extract (a(b)c) and ((d)f(g))", "%b()") do print(s) end
(siehe Demo )Perl6 :
Nicht überlappende Übereinstimmungen mit mehreren ausgeglichenen Klammern:
Überlappende Übereinstimmungen mit mehreren ausgeglichenen Klammern:
Siehe Demo .
Python-
re
Nicht-Regex-LösungSiehe die Antwort von poke für Wie man einen Ausdruck zwischen ausgeglichenen Klammern erhält .
Java anpassbare Nicht-Regex-Lösung
Hier ist eine anpassbare Lösung, die Literaltrennzeichen für einzelne Zeichen in Java ermöglicht:
Beispielnutzung:
quelle
Der reguläre Ausdruck mit Ruby (Version 1.9.3 oder höher):
Demo auf Rubular
quelle
Sie benötigen die erste und letzte Klammer. Verwenden Sie so etwas:
str.indexOf ('('); - gibt Ihnen das erste Auftreten
str.lastIndexOf (')'); - Letzter
Sie benötigen also eine Zeichenfolge zwischen,
quelle
quelle
Die Antwort hängt davon ab, ob Sie übereinstimmende Klammern oder nur das erste Öffnen bis zum letzten Schließen im Eingabetext abgleichen müssen.
Wenn Sie mit übereinstimmenden verschachtelten Klammern übereinstimmen müssen, benötigen Sie mehr als reguläre Ausdrücke. - siehe @dehmann
Wenn es nur vom ersten bis zum letzten Schließen geöffnet ist, siehe @Zach
Entscheiden Sie, womit Sie passieren möchten:
Sie müssen entscheiden, was Ihr Code in diesem Fall übereinstimmen muss.
quelle
Da js regex keine rekursive Übereinstimmung unterstützt, kann ich keine Übereinstimmung mit ausgeglichenen Klammern erzielen.
Dies ist also ein einfaches Javascript für die Schleifenversion, das die Zeichenfolge "method (arg)" in ein Array umwandelt
Das Ergebnis ist wie
quelle
Während so viele Antworten dies in irgendeiner Form erwähnen, indem sie sagen, dass Regex kein rekursives Matching usw. unterstützt, liegt der Hauptgrund dafür in den Wurzeln der Berechnungstheorie.
Sprache der Form
{a^nb^n | n>=0} is not regular
. Regex kann nur mit Dingen übereinstimmen, die Teil des regulären Satzes von Sprachen sind.Lesen Sie mehr @ hier
quelle
Ich habe keinen regulären Ausdruck verwendet, da es schwierig ist, mit verschachteltem Code umzugehen. Mit diesem Snippet sollten Sie also Codeabschnitte mit ausgewogenen Klammern abrufen können:
Ich habe dies verwendet, um Codefragmente aus einer Textdatei zu extrahieren.
quelle
Ich war auch in dieser Situation festgefahren, in der verschachtelte Muster auftreten.
Regulärer Ausdruck ist das Richtige, um das oben genannte Problem zu lösen. Verwenden Sie das folgende Muster
quelle
Dieser hat auch funktioniert
quelle
Dies kann für einige nützlich sein:
Analysieren Sie Parameter aus Funktionszeichenfolgen (mit verschachtelten Strukturen) in Javascript
Übereinstimmende Strukturen wie:
Hier können Sie den generierten regulären Ausdruck in Aktion sehen
Dies behandelt die OP-Frage nicht vollständig, aber ich denke, dass es für einige, die hierher kommen, nützlich sein kann, nach Regexp für verschachtelte Strukturen zu suchen.
quelle