Regex benannte Gruppen in Java

173

Nach meinem Verständnis unterstützt das java.regexPaket keine benannten Gruppen ( http://www.regular-expressions.info/named.html ). Kann mich jemand auf eine Bibliothek eines Drittanbieters hinweisen, die dies tut?

Ich habe mir jregex angesehen, aber seine letzte Veröffentlichung war im Jahr 2002 und es hat bei mir nicht funktioniert (zugegebenermaßen habe ich es nur kurz versucht) unter java5.

Dan
quelle
3
Ihr Verständnis ist falsch. JDK7 behandelt benannte Gruppen.
Tchrist
2
@tchrist Im Jahr 2009 gab es kein JDK7.
Alex78191

Antworten:

275

( Update : August 2011 )

Wie Geofflane in seiner Antwort erwähnt , unterstützt Java 7 jetzt benannte Gruppen .
tchrist weist in dem Kommentar darauf hin, dass die Unterstützung begrenzt ist.
Er beschreibt die Einschränkungen in seiner großartigen Antwort " Java Regex Helper ".

Die Gruppenunterstützung mit dem Namen Java 7 Regex wurde bereits im September 2010 im Oracle-Blog vorgestellt .

In der offiziellen Version von Java 7 sind die Konstrukte zur Unterstützung der genannten Erfassungsgruppe:

  • (?<name>capturing text) um eine benannte Gruppe "Name" zu definieren
  • \k<name> um eine benannte Gruppe "Name" zurück zu referenzieren
  • ${name} um auf die erfasste Gruppe in Matchers Ersatzzeichenfolge zu verweisen
  • Matcher.group(String name) um die erfasste Eingabesubsequenz der angegebenen "benannten Gruppe" zurückzugeben.

Andere Alternativen für Pre-Java 7 waren:


( Ursprüngliche Antwort : Januar 2009 , die nächsten beiden Links sind jetzt defekt)

Sie können nicht auf benannte Gruppen verweisen, es sei denn, Sie codieren Ihre eigene Version von Regex ...

Genau das hat Gorbush2 in diesem Thread getan .

Regex2

(eingeschränkte Implementierung, wie von tchrist erneut ausgeführt , da nur nach ASCII-Bezeichnern gesucht wird. tchrist beschreibt die Einschränkung wie folgt:

Sie können nur eine benannte Gruppe pro Namen haben (über die Sie nicht immer die Kontrolle haben!) und sie nicht für die In-Regex-Rekursion verwenden.

Hinweis: Beispiele für Regex-Rekursionen finden Sie in Perl- und PCRE-Regexen ( siehe Regexp Power , PCRE-Spezifikationen und Folie " Übereinstimmende Zeichenfolgen mit ausgeglichenen Klammern" ).

Beispiel:

String:

"TEST 123"

RegExp:

"(?<login>\\w+) (?<id>\\d+)"

Zugriff

matcher.group(1) ==> TEST
matcher.group("login") ==> TEST
matcher.name(1) ==> login

Ersetzen

matcher.replaceAll("aaaaa_$1_sssss_$2____") ==> aaaaa_TEST_sssss_123____
matcher.replaceAll("aaaaa_${login}_sssss_${id}____") ==> aaaaa_TEST_sssss_123____ 

(Auszug aus der Implementierung)

public final class Pattern
    implements java.io.Serializable
{
[...]
    /**
     * Parses a group and returns the head node of a set of nodes that process
     * the group. Sometimes a double return system is used where the tail is
     * returned in root.
     */
    private Node group0() {
        boolean capturingGroup = false;
        Node head = null;
        Node tail = null;
        int save = flags;
        root = null;
        int ch = next();
        if (ch == '?') {
            ch = skip();
            switch (ch) {

            case '<':   // (?<xxx)  look behind or group name
                ch = read();
                int start = cursor;
[...]
                // test forGroupName
                int startChar = ch;
                while(ASCII.isWord(ch) && ch != '>') ch=read();
                if(ch == '>'){
                    // valid group name
                    int len = cursor-start;
                    int[] newtemp = new int[2*(len) + 2];
                    //System.arraycopy(temp, start, newtemp, 0, len);
                    StringBuilder name = new StringBuilder();
                    for(int i = start; i< cursor; i++){
                        name.append((char)temp[i-1]);
                    }
                    // create Named group
                    head = createGroup(false);
                    ((GroupTail)root).name = name.toString();

                    capturingGroup = true;
                    tail = root;
                    head.next = expr(tail);
                    break;
                }
VonC
quelle
beide Links oben scheinen kaputt zu sein?
Jonas
Dieser Code ist fehlerhaft. Es wird nach ASCII-Kennungen gesucht. Das ist falsch. Es sollte nach allem suchen, was Java in einem Bezeichner zulässt !!
Tchrist
1
Nur zu Ihrer Information, da Sie so gewissenhaft erscheinen, geht es in dem begrenzten Teil nicht so sehr um die ASCII- oder Unicode-Namen, sondern darum, nur eine benannte Gruppe pro Namen zu haben (über die Sie nicht immer die Kontrolle haben!) Und Sie können sie nicht für die In-Regex-Rekursion verwenden.
Tchrist
@tchrist: Danke für diese Präzision (im Lieferumfang enthalten). Ich habe auch einen Link zurück zu Ihrer herausragenden Antwort auf "Java Regex Helper" (upvoted) hinzugefügt.
VonC
Es gibt keine matcher.name (int index) Methode für Matcher Objekt in Java?
ot0
27

Ja, aber es ist chaotisch, die Sonnenklassen zu hacken. Es gibt einen einfacheren Weg:

http://code.google.com/p/named-regexp/

named-regexp ist ein Thin Wrapper für die Standardimplementierung regulärer JDK-Ausdrücke mit dem einzigen Zweck, benannte Erfassungsgruppen im .net-Stil zu behandeln: (? ...).

Es kann mit Java 5 und 6 verwendet werden (Generika werden verwendet).

Java 7 verarbeitet benannte Erfassungsgruppen, sodass dieses Projekt nicht von Dauer ist.

John Hardy
quelle
1
Schade, dass dies nicht innerhalb von GWT verwendet werden kann.
Sakuraba
4
Schauen Sie sich die GitHub-Gabel dieses Projekts an, die mehrere Fehler aus dem Original behebt. Es wird auch in Maven Central gehostet.
Tony19
1
Nur ein Wort der Vorsicht in meinem Fall, die Tony19-Gabel auf Github funktioniert unter Android ab 0.1.8 nicht mehr.
Chuck D
2
@ RubberMallet, Das Android-spezifische Problem ist jetzt behoben und wird in 0.1.9 sein.
Tony19
2

Was für ein Problem haben Sie mit Jregex ? Es hat gut für mich unter Java5 und Java6 funktioniert.

Jregex macht den Job gut (auch wenn die letzte Version aus dem Jahr 2002 stammt), es sei denn, Sie möchten auf JavaSE 7 warten .

Brian Clozel
quelle
2

Für diejenigen, die Pre-Java7 ausführen, werden benannte Gruppen von Joni (Java-Port der Oniguruma- Regexp-Bibliothek) unterstützt. Die Dokumentation ist spärlich, hat aber bei uns gut funktioniert.
Binärdateien sind über Maven verfügbar ( http://repository.codehaus.org/org/jruby/joni/joni/ ).

Ryan Smith
quelle
Ich bin sehr interessiert an der von Ryan oben erwähnten Joni-Option - haben Sie Codefragmente mit benannten Erfassungsgruppen - Ich habe es geschafft, grundlegende Übereinstimmungen und Suchen zu erhalten, um richtig zu funktionieren - aber ich sehe nicht, welche Methode ich verwenden würde Zugriff auf die Gruppennamen erhalten oder den Wert eines Captures mithilfe des Gruppennamens abrufen.
Malsmith
1

Eine etwas alte Frage, aber ich brauchte sie auch und dass die obigen Vorschläge unzureichend waren - und als solche selbst eine dünne Hülle entwickelten: https://github.com/hofmeister/MatchIt

Henrik Hofmeister
quelle