Classi di caratteri Regex in Java
Classi di caratteri predefinite e personalizzate in Java regex — \d, \w, \s, intervalli, negazioni e intersezioni.
Una classe di caratteri è la parte di un'espressione regolare che corrisponde a un carattere tra un insieme di caratteri ammessi. Ogni volta che scrivi \d, [aeiou] o [^0-9], stai usando una classe di caratteri. Sono il mattone più piccolo di quasi ogni pattern utile, e il motore java.util.regex di Java ne offre tre tipi: abbreviazioni già pronte come \d, insiemi personalizzati specificati in [...], e classi con nome compatibili con Unicode come \p{Lower}. Padroneggiare questi strumenti rende il resto delle regex molto più semplice.
Questo capitolo tratta tutti e tre i tipi — classi a parentesi quadre con intervalli e negazione, le abbreviazioni predefinite, le operazioni su insiemi (unione, intersezione, sottrazione) e le classi con nome Unicode/POSIX — e li collega in un programma eseguibile. Se sei nuovo alle regex in Java, inizia prima con l'introduzione alle regex e la sintassi delle regex.
Classi personalizzate: parentesi quadre, intervalli e negazione
La classe a parentesi quadre [...] corrisponde a qualsiasi carattere singolo elencato al suo interno. Puoi elencare i caratteri uno per uno, oppure usare un trattino per esprimere un intervallo. Inserire ^ subito dopo la parentesi aperta nega l'insieme — corrisponde a qualsiasi carattere che non è elencato.
"[abc]" // matches one 'a', 'b', or 'c'
"[a-z]" // any one lowercase letter (a range)
"[A-Za-z0-9]"// any letter or digit (three ranges in one class)
"[^aeiou]" // any single character that is NOT a vowelAll'interno di una classe, la maggior parte dei metacaratteri perde il proprio significato speciale, quindi raramente è necessario fare l'escape. L'eccezione sono ], ^, - e \ letterali — eseguine l'escape, oppure posizionali in modo che non possano essere mal interpretati (un - in prima o ultima posizione è un trattino letterale, non un intervallo).
java.util.regex.Pattern p = java.util.regex.Pattern.compile("[-+0-9]");
System.out.println(p.matcher("-").find()); // true: leading - is literal
System.out.println(p.matcher("*").find()); // falseClassi predefinite: le abbreviazioni
Java fornisce abbreviazioni per gli insiemi che usi più spesso. Ogni forma minuscola ha un complemento maiuscolo che corrisponde a tutto ciò che la forma minuscola non corrisponde.
| Abbreviazione | Corrisponde a | Classe equivalente |
|---|---|---|
. | qualsiasi carattere tranne i terminatori di riga | — |
\d | una cifra | [0-9] |
\D | un non-cifra | [^0-9] |
\w | un carattere di parola | [a-zA-Z_0-9] |
\W | un carattere non di parola | [^a-zA-Z_0-9] |
\s | un carattere di spazio bianco | [ \t\n\x0B\f\r] |
\S | un carattere non di spazio bianco | [^\s] |
\d si scrive "\\d" in un literal di stringa, e \w diventa "\\w". Dimenticare il secondo backslash è l'errore più comune nelle regex Java — "\d" non compila nemmeno.String digits = "\\d+"; // regex is \d+ (one or more digits)
String word = "\\w+"; // regex is \w+
"abc123".replaceAll("\\d", "#"); // "abc###"Negazione, intersezione e unione
Una classe a parentesi quadre è un'unione per impostazione predefinita — elenca [abcxyz] e corrisponde a uno qualsiasi dei sei caratteri. Java aggiunge due operatori di insieme all'interno delle classi. L'operatore && forma un'intersezione (corrisponde solo ai caratteri presenti in entrambi gli insiemi), e nidificare una classe dentro un'altra permette di sottrarre.
| Costrutto | Significato |
|---|---|
[a-d[m-p]] | unione: da a a d oppure da m a p |
[a-z&&[aeiou]] | intersezione: lettere minuscole che sono vocali |
[a-z&&[^aeiou]] | sottrazione: lettere minuscole che non sono vocali (consonanti) |
"[a-z&&[^aeiou]]" // all lowercase consonants
"[\\p{L}&&[^\\p{Lu}]]" // any letter that is not uppercaseLa negazione con ^ inverte un'intera classe; l'intersezione con && la restringe. Scegliere quello giusto mantiene i pattern leggibili invece di accumulare alternanze.
Classi con nome Unicode e POSIX
Per qualsiasi cosa al di là dell'ASCII, usa la famiglia \p{...}. Queste classi con nome conoscono le categorie Unicode e i gruppi in stile POSIX, e \P{...} è la forma negata. Sono essenziali quando l'input contiene lettere accentate, scritture non latine, o semplicemente vuoi nomi che esprimano chiaramente l'intenzione.
| Classe | Corrisponde a |
|---|---|
\p{Lower} | una lettera ASCII minuscola ([a-z]) |
\p{Punct} | un carattere di punteggiatura |
\p{Alnum} | una lettera ASCII o una cifra |
\p{L} | qualsiasi lettera Unicode (con UNICODE_CHARACTER_CLASS) |
\p{IsDigit} | una cifra Unicode |
// Make \w, \d, \s honor full Unicode, not just ASCII:
java.util.regex.Pattern uni =
java.util.regex.Pattern.compile("\\w+", java.util.regex.Pattern.UNICODE_CHARACTER_CLASS);
System.out.println(uni.matcher("café").results().count()); // 1: "café" is one wordUn esempio pratico: ogni tipo di classe su una stringa
Questo programma costruisce un piccolo helper, count, che riporta quanti caratteri di una stringa campione corrispondono a una classe di un carattere. Eseguire la stessa stringa attraverso cifre, parole, spazi bianchi, intervalli, negazione, intersezione, il punto e una classe POSIX rende concreti i rapporti tra loro — e mostra una classe al lavoro all'interno di un pattern più grande.
Cosa ricavare dall'esecuzione:
\de[0-9]riportano entrambi 13 per questa stringa — sono esattamente equivalenti per input ASCII. Una classe predefinita è semplicemente un nome incorporato per un insieme che potresti scrivere a mano, quindi usa l'abbreviazione per migliorare la leggibilità.\De[^0-9]riportano entrambi 30, il complemento delle 13 cifre in una stringa di 43 caratteri (13 + 30 = 43). Un'abbreviazione maiuscola e una classe a parentesi quadre negata sono due modi di scrivere lo stesso complemento.[a-z&&[aeiou]]riporta 3 — solo le vocali minuscole, che sono laedi Order, laodi cost e laidi ship-by. LaOmaiuscola di Order è in maiuscolo, quindi l'intersezione la esclude. Il punto:&&restringe una classe ai caratteri presenti in entrambi gli insiemi anziché unirli, quindi le vocali maiuscole non si qualificano mai.- Il punto ha corrisposto a 43 caratteri, ogni carattere inclusi spazi e punteggiatura, perché questa stringa su riga singola non ha terminatori di riga su cui
.si fermi. Il punto è la classe più ampia di tutte, il che è esattamente il motivo per cui di solito lo si sostituisce con una più specifica. - Il pattern
[A-Z]\dha trovatoA7: le classi di caratteri non servono solo per contare — combinate in una sequenza validano la struttura, qui una lettera immediatamente seguita da una cifra.\p{Punct}separatamente ha trovato 9 segni di punteggiatura, mostrando che le classi POSIX con nome funzionano insieme alle abbreviazioni.
Esercizio
Dove andare dopo
Una classe di caratteri corrisponde a un carattere; il passo successivo è controllare quanti ne fai corrispondere e cosa fare con il risultato:
- Quantificatori regex — aggiungi
+,*,?e{n,m}per far corrispondere a una classe una sequenza di caratteri. - Gruppi di cattura — racchiudi una classe in
(...)per estrarre una sottostringa corrispondente. - Pattern e Matcher — l'API usata in ogni esempio precedente, in dettaglio.
- Flag regex —
CASE_INSENSITIVE,UNICODE_CHARACTER_CLASSe gli altri che modificano il comportamento delle classi.