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.