W3docs

Gruppi e Catture nelle Regex Java

Cattura parti del testo corrispondente in Java con parentesi, gruppi numerati e gruppi con nome nelle espressioni regolari.

Un'espressione regolare non si limita a dirti se una stringa corrisponde—può suddividere la corrispondenza in parti che puoi leggere. Queste parti sono i gruppi. Racchiudendo una parte del pattern tra parentesi si crea un gruppo di cattura, e una volta che un Matcher ha trovato una corrispondenza puoi estrarre ciascun gruppo tramite numero o nome. Questo capitolo tratta i gruppi numerati, i gruppi con nome, i backreference, i gruppi non catturanti e come si usano nei rimpiazzi.

Gruppi di Cattura Numerati

Ogni coppia di parentesi in un pattern apre un gruppo di cattura, numerato da sinistra a destra dalla ( di apertura. Il gruppo 0 è speciale: corrisponde sempre all'intera corrispondenza. Quindi (\d{4})-(\d{2})-(\d{2}) fornisce quattro gruppi—l'intera data più anno, mese e giorno.

Pattern p = Pattern.compile("(\\d{4})-(\\d{2})-(\\d{2})");
Matcher m = p.matcher("2026-05-30");
if (m.matches()) {
    System.out.println(m.group(0)); // 2026-05-30 (entire match)
    System.out.println(m.group(1)); // 2026
    System.out.println(m.group(2)); // 05
    System.out.println(m.group(3)); // 30
}

groupCount() restituisce il numero di gruppi di cattura escluso il gruppo 0, quindi il pattern precedente riporta 3. Leggere un indice di gruppo inesistente lancia un IndexOutOfBoundsException.

Gruppi con Nome

Contare le parentesi diventa fragile man mano che i pattern crescono. I gruppi con nome, scritti (?<name>...), permettono di leggere una cattura tramite un'etichetta leggibile invece di un indice. I nomi devono essere identificatori Java validi e unici all'interno del pattern.

Pattern p = Pattern.compile("(?<user>[\\w.]+)@(?<host>[\\w.]+)");
Matcher m = p.matcher("[email protected]");
if (m.matches()) {
    System.out.println(m.group("user")); // ada
    System.out.println(m.group("host")); // math.org
}

I gruppi con nome sono comunque numerati internamente, quindi m.group(1) e m.group("user") restituiscono lo stesso testo. Il nome è puramente per la leggibilità del codice.

Backreference

Un backreference corrisponde allo stesso testo già catturato da un gruppo precedente. All'interno del pattern si scrive \1 per il gruppo 1 (oppure \k<name> per un gruppo con nome). È così che si rileva una ripetizione—ad esempio una parola raddoppiata—all'interno di una singola corrispondenza.

// \b(\w+)\s+\1\b  matches a word followed by the same word again
Pattern p = Pattern.compile("\\b(\\w+)\\s+\\1\\b");
Matcher m = p.matcher("the the end");
if (m.find()) {
    System.out.println(m.group(1)); // the
}

Si noti il doppio backslash nel sorgente Java: \\1 nella stringa diventa \1 nella regex reale. Un backreference può corrispondere solo dopo che il suo gruppo ha catturato, quindi il gruppo deve apparire prima nel pattern.

Gruppi di Cattura nei Rimpiazzi

String.replaceAll, Matcher.replaceAll e appendReplacement comprendono tutti i riferimenti ai gruppi nel testo di rimpiazzo. Usa $1, $2, ... per i gruppi numerati e ${name} per quelli con nome. Questo trasforma le regex in un piccolo strumento di riordinamento e formattazione.

RiferimentoSignificato nel rimpiazzo
$0L'intera corrispondenza
$1, $2, ...Gruppi di cattura numerati
${name}Un gruppo di cattura con nome
\$Un segno dollaro letterale
// Reorder "First Last" into "Last, First"
String out = "Ada Lovelace".replaceAll("(\\w+)\\s+(\\w+)", "$2, $1");
System.out.println(out); // Lovelace, Ada

Se hai bisogno di un $ o \ letterale nell'output, esegui l'escape come \\$ o \\\\ nella stringa Java.

Gruppi Non Catturanti

A volte le parentesi servono solo per raggruppare un'alternanza o applicare un quantificatore—non per catturare. Un gruppo non catturante (?:...) fa esattamente questo: raggruppa senza consumare un numero di gruppo, mantenendo puliti gli indici e rendendo il motore leggermente più veloce.

// Group the protocol alternation, but capture only the host
Pattern p = Pattern.compile("(?:https?|ftp)://(\\S+)");
Matcher m = p.matcher("https://w3docs.com");
if (m.find()) {
    System.out.println(m.group(1)); // w3docs.com  (group 1, not 2)
}

Poiché (?:https?|ftp) è non catturante, l'host è il gruppo 1 anziché il gruppo 2. Un gruppo di cattura opzionale che non partecipa alla corrispondenza restituisce null, quindi controlla sempre null sui gruppi opzionali prima di usarli.

Un Esempio Eseguibile

Il programma seguente esercita ogni tipo di gruppo in un'unica esecuzione: parti numeriche di una data, campi email con nome, un backreference per parola raddoppiata, riferimenti di gruppo in due rimpiazzi, un gruppo non catturante per il protocollo e un gruppo opzionale che restituisce null.

java— editable, runs on the server

Cosa osservare dall'esecuzione:

  • Le due righe della data mostrano i gruppi numerati: group(0) è l'intera corrispondenza mentre group(1..3) sono anno, mese e giorno catturati per posizione.
  • La riga dell'email dimostra che i gruppi con nome leggono lo stesso testo degli indici, e groupCount=2 conta solo le catture con nome, mai il gruppo 0.
  • Doubled: the e Doubled: sat provengono dal backreference \1 che corrisponde a qualunque cosa il gruppo della parola abbia appena catturato—ogni parola ripetuta viene trovata indipendentemente.
  • Swapped: Lovelace, Ada, Turing, Alan mostra $2, $1 che riordina ogni coppia di nomi, mentre Masked: card [4111] [2222] mostra il riferimento con nome ${num} che formatta l'output.
  • Il (?:https?|ftp) non catturante mantiene l'host al gruppo 1 (w3docs.com), e il gruppo della frazione opzionale stampa frac=null perché non ha mai partecipato alla corrispondenza di 42.

Dove Andare Dopo

I gruppi si basano sul resto del motore regex, quindi è utile avere familiarità con le parti circostanti:

  • Pattern e Matcher — le classi i cui metodi group(), groupCount() e replaceAll() vengono chiamati qui.
  • Quantificatori Regex{4}, + e ? decidono quanto cattura ciascun gruppo.
  • Classi di Caratteri Regex\d, \w e \S sono i componenti di cui sono fatti la maggior parte dei gruppi.
  • Flag Regex — flag come CASE_INSENSITIVE cambiano cosa corrispondono i tuoi gruppi.

Esercitazione

Pratica
Nel pattern (?:https?|ftp)://(\S+), quale gruppo contiene la porzione host catturata da (\S+)?
Nel pattern (?:https?|ftp)://(\S+), quale gruppo contiene la porzione host catturata da (\S+)?
Was this page helpful?