Regex Named Groups in Java


173

Comprendo che il java.regexpacchetto non ha supporto per i gruppi con nome ( http://www.regular-expressions.info/named.html ), quindi qualcuno può indirizzarmi verso una libreria di terze parti che lo fa?

Ho guardato jregex ma la sua ultima versione è stata nel 2002 e non ha funzionato per me (devo ammetterlo solo brevemente) con java5.


3
La tua comprensione è errata. JDK7 gestisce gruppi denominati.
tchrist,

2
@tchrist Nel 2009 non c'era JDK7.
Alex78191,

Risposte:


276

( Aggiornamento : agosto 2011 )

Come menziona geofflane nella sua risposta , Java 7 ora supporta gruppi denominati .
tchrist sottolinea nel commento che il supporto è limitato.
Descrive in dettaglio i limiti nella sua grande risposta " Java Regex Helper "

Il supporto del gruppo denominato regex Java 7 è stato presentato nel settembre 2010 nel blog di Oracle .

Nella versione ufficiale di Java 7, i costrutti per supportare il gruppo di acquisizione denominato sono:

  • (?<name>capturing text) definire un "nome" di gruppo denominato
  • \k<name> per fare riferimento a un gruppo denominato "nome"
  • ${name} per fare riferimento al gruppo acquisito nella stringa di sostituzione del Matcher
  • Matcher.group(String name) per restituire la sottosequenza di input acquisita dal "gruppo denominato" indicato.

Altre alternative per pre-Java 7 erano:


( Risposta originale : gennaio 2009 , con i due collegamenti successivi ora interrotti)

Non è possibile fare riferimento al gruppo denominato, a meno che non si codifichi la propria versione di Regex ...

Questo è esattamente ciò che Gorbush2 ha fatto in questo thread .

Regex2

(implementazione limitata, come sottolineato ancora da tchrist , in quanto cerca solo identificatori ASCII. tchrist specifica la limitazione come:

solo essere in grado di avere un gruppo nominato per lo stesso nome (di cui non si ha sempre il controllo!) e non essere in grado di usarli per la ricorsione in-regex.

Nota: è possibile trovare veri esempi di ricorsione regex nelle regex Perl e PCRE, come indicato in Regexp Power , specifiche PCRE e stringhe di corrispondenza con diapositiva Parentesi bilanciate )

Esempio:

Corda:

"TEST 123"

RegExp:

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

Accesso

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

Sostituire

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

(estratto dall'attuazione)

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;
                }

entrambi i collegamenti sopra sembrano essere interrotti?
Jonas,

Questo codice è difettoso. Sta cercando identificatori ASCII. È sbagliato. Dovrebbe cercare tutto ciò che Java consente in un identificatore !!
tchrist,

1
Cordiali saluti dato che sembri così coscienzioso, la parte limitata non riguarda tanto i nomi ASCII vs Unicode in quanto si tratta solo di avere un solo gruppo con lo stesso nome (di cui non hai sempre il controllo!) E non essere in grado di usarli per la ricorsione in-regex.
tchrist,

@tchrist: grazie per questa precisione (inclusa). Ho anche aggiunto un link alla tua risposta stellare su "Helper Java Regex" (votato).
VonC,

Non esiste un metodo matcher.name (int index) per l'oggetto Matcher in Java ??
ot0


27

Sì, ma è disordinato hackerare le classi del sole. C'è un modo più semplice:

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

named-regexp è un wrapper sottile per l'implementazione standard delle espressioni regolari JDK, con l'unico scopo di gestire i gruppi di acquisizione denominati nello stile .net: (? ...).

Può essere utilizzato con Java 5 e 6 (vengono utilizzati generici).

Java 7 gestirà i gruppi di acquisizione denominati, quindi questo progetto non è destinato a durare.


1
Peccato che questo non possa essere utilizzato da GWT.
Sakuraba,

4
Dai un'occhiata al fork di GitHub di questo progetto, che risolve diversi bug dall'originale. È anche ospitato a Maven Central.
tony19

1
Solo una parola di cautela nel mio caso, il fork tony19 su Github non funziona su Android a partire da 0.1.8.
Chuck D,

2
@RubberMallet, Il problema specifico di Android è stato risolto e sarà in 0.1.9.
tony19


2

Per coloro che eseguono pre-java7, i gruppi con nome sono supportati da joni (porta Java della libreria regexp di Oniguruma ). La documentazione è scarsa, ma ha funzionato bene per noi.
I binari sono disponibili via Maven ( http://repository.codehaus.org/org/jruby/joni/joni/ ).


Sono molto interessato all'opzione joni menzionata da Ryan sopra - hai qualche frammento di codice usando gruppi di acquisizione con nome - Sono riuscito a ottenere la corrispondenza di base e la ricerca per funzionare correttamente - ma non vedo quale metodo utilizzare ottenere l'accesso a groupNames o per ottenere il valore di una cattura usando il nome del gruppo.
malsmith,

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.