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.