Java regex che cattura gli indici dei gruppi


113

Ho la seguente riga,

typeName="ABC:xxxxx;";

Ho bisogno di prendere la parola ABC,

Ho scritto il seguente snippet di codice,

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

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

}

Quindi se metto group(0)ottengo ABC:ma se lo metto group(1)lo è ABC, quindi voglio sapere

  1. Cosa significa questo 0e 1? Sarà meglio se qualcuno mi può spiegare con buoni esempi.

  2. Il pattern regex contiene un :al suo interno, quindi perché il group(1)risultato lo omette? Il gruppo 1 rileva tutte le parole all'interno delle parentesi?

  3. Quindi, se metto altre due parentesi come,: \\s*(\d*)(.*)allora, ci saranno due gruppi? group(1)restituirà la (\d*)parte e group(2)restituirà la (.*)parte?

Lo snippet di codice è stato fornito allo scopo di chiarire le mie confusioni. Non è il codice con cui ho a che fare. Il codice sopra riportato può essere utilizzato String.split()in modo molto più semplice.

Risposte:


182

Cattura e raggruppamento

L'acquisizione del gruppo (pattern) crea un gruppo con proprietà di acquisizione .

Uno correlato che potresti vedere (e utilizzare) spesso è (?:pattern), che crea un gruppo senza acquisire proprietà, quindi denominato gruppo non di acquisizione .

Un gruppo viene solitamente utilizzato quando è necessario ripetere una sequenza di modelli, ad esempio (\.\w+)+, o per specificare dove deve avere effetto l'alternanza, ad esempio ^(0*1|1*0)$( ^, then 0*1or 1*0, then $) contro ^0*1|1*0$( ^0*1o 1*0$).

Un gruppo di acquisizione, oltre al raggruppamento, registrerà anche il testo corrispondente al modello all'interno del gruppo di acquisizione (pattern). Usando il tuo esempio, (.*):, .*le partite ABCe :le partite :, e dal momento che .*è dentro gruppo di cattura (.*), il testo ABCviene registrato per il gruppo di cattura 1.

Numero del gruppo

L'intero modello è definito come il numero di gruppo 0.

Qualsiasi gruppo di acquisizione nel modello inizia l'indicizzazione da 1. Gli indici sono definiti dall'ordine delle parentesi di apertura dei gruppi di acquisizione . Ad esempio, ecco tutti e 5 i gruppi di acquisizione nel modello seguente:

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

I numeri di gruppo vengono utilizzati come riferimento \na ritroso nel modello e $nnella stringa di sostituzione.

In altre versioni regex (PCRE, Perl), possono essere utilizzate anche nelle chiamate di sub-routine .

È possibile accedere al testo abbinato da un determinato gruppo con Matcher.group(int group). I numeri di gruppo possono essere identificati con la regola sopra indicata.

In alcune versioni di espressioni regolari (PCRE, Perl), è presente una funzione di ripristino dei rami che consente di utilizzare lo stesso numero per acquisire gruppi in diversi rami di alternanza .

Nome del gruppo

Da Java 7, è possibile definire un gruppo di acquisizione denominato (?<name>pattern) e accedere al contenuto abbinato a Matcher.group(String name). La regex è più lunga, ma il codice è più significativo, poiché indica cosa stai cercando di abbinare o estrarre con la regex.

I nomi dei gruppi vengono utilizzati come riferimento \k<name>a ritroso nel modello e ${name}nella stringa di sostituzione.

I gruppi di acquisizione con nome sono ancora numerati con lo stesso schema di numerazione, quindi è possibile accedervi anche tramite Matcher.group(int group).

Internamente, l'implementazione di Java si limita a mappare dal nome al numero del gruppo. Pertanto, non è possibile utilizzare lo stesso nome per 2 diversi gruppi di acquisizione.


1
WOW! Grazie @nhahtdh per aver spiegato i gruppi che non catturano come funziona l'ordine dei gruppi di nidificazione. Ero perplesso su come funzionassero i numeri del gruppo finché non ho finalmente letto la tua spiegazione. Molte grazie!
MMeah

92

Per il resto di noi

Ecco un esempio semplice e chiaro di come funziona

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

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

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

Come puoi vedere, ho creato CINQUE gruppi, ciascuno racchiuso tra parentesi.

Ho incluso! * E *! su entrambi i lati per renderlo più chiaro. Notare che nessuno di questi caratteri si trova nella RegEx e quindi non verrà prodotto nei risultati. Il gruppo (0) ti fornisce semplicemente l'intera stringa corrispondente (tutti i miei criteri di ricerca in una singola riga). Il gruppo 1 si ferma subito prima del primo spazio perché il carattere spazio non è stato incluso nei criteri di ricerca. I gruppi 2 e 4 sono semplicemente lo spazio bianco, che in questo caso è letteralmente un carattere di spazio, ma potrebbe anche essere una tabulazione o un avanzamento riga ecc. Il gruppo 3 include lo spazio perché l'ho inserito nei criteri di ricerca ... ecc.

Spero che questo abbia un senso.


1
esempio perfetto che è facile da capire per i principianti. Ho un dubbio che sia lo stesso del raggruppamento reg ex in Python? oppure c'è qualche differenza? sono nuovo in reg ex, ecco perché sono un po 'confuso in entrambe le lingue.
Mani

1
Questa non è una regex Java valida: i backslash devono essere raddoppiati.
Nicolas Raoul

1
@NicolasRaoul: il doppio backslash è dovuto alla sintassi di escape nella stringa letterale. L'attuale sintassi regex (cioè se si stampa la stringa contenente la regex sulla console) non richiede una doppia barra rovesciata.
nhahtdh

@NicolasRaoul Se dovessi copiare e incollare la mia stringa regex nel codice java effettivo utilizzando un IDE competente, l'IDE formatterebbe correttamente le barre di escape come necessario. Ma il mio Regex è tecnicamente e sintatticamente corretto e serve allo scopo principale che è quello di dimostrare l'associazione tra il codice regex ei risultati ottenuti (usando un esempio molto specifico) ... alleggerire un po '... ☺
Michael Sims

44

Le parentesi ()vengono utilizzate per abilitare il raggruppamento di frasi regex.

Il group(1)contiene la stringa che è tra parentesi (.*)quindi .*in questo caso

E group(0)contiene l'intera stringa corrispondente.

Se avessi più gruppi (letti (...)), verrebbero messi in gruppi con indici successivi (2, 3 e così via).


2
Quindi, ho ragione sul fatto che l'aggiunta di parentesi sia effettivamente per la creazione di gruppi?
P basak

3
Sì, possiamo dirlo.
Michal Borek
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.