Java Regex erfasst Gruppenindizes

113

Ich habe die folgende Zeile:

typeName="ABC:xxxxx;";

Ich muss das Wort holen ABC,

Ich habe das folgende Code-Snippet geschrieben:

Pattern pattern4=Pattern.compile("(.*):");
matcher=pattern4.matcher(typeName);

String nameStr="";
if(matcher.find())
{
    nameStr=matcher.group(1);

}

Also , wenn ich legte group(0)ich ABC:aber , wenn ich legte group(1)es ist ABC, so ich wissen will ,

  1. Was bedeutet das 0und was 1? Es ist besser, wenn mich jemand mit guten Beispielen erklären kann.

  2. Das Regex-Muster enthält ein :darin. Warum group(1)lässt das Ergebnis das aus? Erkennt Gruppe 1 alle Wörter in Klammern?

  3. Wenn ich also zwei weitere Klammern wie \\s*(\d*)(.*): setze , gibt es dann zwei Gruppen? group(1)wird das (\d*)Teil zurückgeben und group(2)das (.*)Teil zurückgeben?

Das Code-Snippet wurde gegeben, um meine Verwirrungen zu beseitigen. Es ist nicht der Code, mit dem ich es zu tun habe. Der oben angegebene Code kann mit ausgeführt werdenString.split() viel einfacher verwendet werden.

P basak
quelle

Antworten:

182

Erfassen und Gruppieren

Erfassungsgruppe (pattern) erstellt eine Gruppe mit Erfassungseigenschaft .

Eine verwandte, die Sie häufig sehen (und verwenden), ist die (?:pattern), die eine Gruppe erstellt, ohne die Eigenschaft zu erfassen , daher benannt nicht erfassende Gruppe bezeichnet wird .

Eine Gruppe wird normalerweise verwendet, wenn Sie eine Folge von Mustern wiederholen müssen, z. B. (\.\w+)+oder um anzugeben, wo die Abwechslung wirksam werden soll, z. B. ^(0*1|1*0)$( ^, dann 0*1oder 1*0, dann $) gegen ^0*1|1*0$( ^0*1oder1*0$ ).

Eine Erfassungsgruppe zeichnet neben der Gruppierung auch den Text auf, der mit dem Muster innerhalb der Erfassungsgruppe übereinstimmt (pattern). Mit Ihrem Beispiel (.*):, .*Spiele ABCund :Matches :, und da .*ist innerhalb Erfassung Gruppe (.*), der TextABC für die Erfassungsgruppe 1 aufgezeichnet.

Gruppennummer

Das gesamte Muster ist definiert Gruppennummer 0 sein.

Jede Erfassungsgruppe im Muster beginnt mit der Indizierung ab 1. Die Indizes werden durch die Reihenfolge der öffnenden Klammern der Erfassungsgruppen definiert . Als Beispiel sind hier alle 5 Erfassungsgruppen im folgenden Muster aufgeführt:

(group)(?:non-capturing-group)(g(?:ro|u)p( (nested)inside)(another)group)(?=assertion)
|     |                       |          | |      |      ||       |     |
1-----1                       |          | 4------4      |5-------5     |
                              |          3---------------3              |
                              2-----------------------------------------2

Die Gruppennummern werden als Rückverweis \nim Muster und $nals Ersatzzeichenfolge verwendet.

In anderen Regex-Varianten (PCRE, Perl) können sie auch in Subroutinenaufrufen verwendet werden .

Sie können auf den Text zugreifen, mit dem eine bestimmte Gruppe übereinstimmt Matcher.group(int group). Die Gruppennummern können mit der oben angegebenen Regel identifiziert werden.

In einigen Regex-Varianten (PCRE, Perl) gibt es eine Funktion zum Zurücksetzen von Zweigen , mit der Sie dieselbe Nummer zum Erfassen von Gruppen in verschiedenen Zweigen des Wechsels verwenden können .

Gruppenname

In Java 7 können Sie eine benannte Erfassungsgruppe definieren (?<name>pattern) und auf den Inhalt zugreifen, der mit übereinstimmt Matcher.group(String name). Der reguläre Ausdruck ist länger, aber der Code ist aussagekräftiger, da er angibt, was Sie mit dem regulären Ausdruck abgleichen oder extrahieren möchten.

Die Gruppennamen werden in der Rückreferenz \k<name>in Muster und verwendet${name} in der Ersatzzeichenfolge verwendet.

Benannt einfangenden Gruppen sind immer noch mit der gleichen Nummerierungsschema nummeriert, so können sie auch über zugegriffen werden Matcher.group(int group).

Intern ordnet die Java-Implementierung nur den Namen der Gruppennummer zu. Daher können Sie nicht denselben Namen für zwei verschiedene Erfassungsgruppen verwenden.

nhahtdh
quelle
1
BEEINDRUCKEND! Vielen Dank an @nhahtdh, dass Sie nicht erfassenden Gruppen erklärt haben, wie die Reihenfolge der Verschachtelungsgruppen funktioniert. Ich war ratlos darüber, wie die Gruppennummern funktionierten, bis ich endlich Ihre Erklärung las. Vielen Dank!
MMeah
92

Für den Rest von uns

Hier ist ein einfaches und klares Beispiel dafür, wie dies funktioniert

Regex: ([a-zA-Z0-9]+)([\s]+)([a-zA-Z ]+)([\s]+)([0-9]+)

String: "!* UserName10 John Smith 01123 *!"

group(0): UserName10 John Smith 01123
group(1): UserName10
group(2):  
group(3): John Smith
group(4):  
group(5): 01123

Wie Sie sehen können, habe ich FÜNF Gruppen erstellt, die jeweils in Klammern stehen.

Ich habe die! * Und *! auf beiden Seiten, um es klarer zu machen. Beachten Sie, dass sich keines dieser Zeichen in der RegEx befindet und daher nicht in den Ergebnissen erzeugt wird. Gruppe (0) gibt Ihnen lediglich die gesamte übereinstimmende Zeichenfolge (alle meine Suchkriterien in einer einzigen Zeile). Gruppe 1 stoppt direkt vor dem ersten Leerzeichen, da das Leerzeichen nicht in den Suchkriterien enthalten war. Die Gruppen 2 und 4 sind einfach das Leerzeichen, das in diesem Fall buchstäblich ein Leerzeichen ist, aber auch ein Tabulator oder ein Zeilenvorschub usw. sein kann. Gruppe 3 enthält das Leerzeichen, weil ich es in die Suchkriterien eingefügt habe ... usw.

Hoffe das macht Sinn.

Michael Sims
quelle
1
perfektes Beispiel, das für Anfänger leicht zu verstehen ist. Ich habe einen Zweifel, ist dies das gleiche wie reg ex Gruppierung in Python? oder gibt es sonst einen unterschied? Ich bin neu bei Reg Ex, deshalb bin ich in beiden Sprachen ein bisschen verwirrt.
Mani
1
Dies ist kein gültiger Java-Regex: Backslashes müssen verdoppelt werden.
Nicolas Raoul
1
@NicolasRaoul: Doppelter Backslash ist auf die Escape-Syntax im String-Literal zurückzuführen. Die eigentliche Regex-Syntax (dh wenn Sie die Zeichenfolge mit dem Regex an die Konsole drucken) erfordert keinen doppelten Backslash.
nhahtdh
@NicolasRaoul Wenn Sie meine Regex-Zeichenfolge mit einer kompetenten IDE kopieren und in den tatsächlichen Java-Code einfügen würden, würde die IDE die Escape-Schrägstriche nach Bedarf ordnungsgemäß formatieren. Aber mein Regex ist technisch und syntaktisch korrekt und dient hauptsächlich dem Zweck, die Assoziation zwischen Regex-Code und den erzielten Ergebnissen zu demonstrieren (anhand eines sehr spezifischen Beispiels) ... ein wenig aufzuhellen ... ☺
Michael Sims
44

Klammern ()werden verwendet, um die Gruppierung von Regex-Phrasen zu ermöglichen.

Das group(1)enthält die Zeichenfolge , die zwischen Klammern ist (.*)so .*in diesem Fall

Und group(0)enthält ganze übereinstimmende Zeichenfolge.

Wenn Sie mehr Gruppen hätten (lesen (...)), würden diese in Gruppen mit den nächsten Indizes (2, 3 usw.) eingeteilt.

Michal Borek
quelle
2
Ich habe also Recht, dass das Hinzufügen von Klammern tatsächlich zum Erstellen von Gruppen dient.
P basak
3
Ja, das können wir sagen.
Michal Borek