Sintassi delle Regex in Java
Sintassi delle espressioni regolari in Java: caratteri, classi, ancoraggi, quantificatori e costrutti speciali.
Un'espressione regolare è un piccolo linguaggio di pattern per descrivere testo. Java la implementa nel package java.util.regex, e la sintassi è il dialetto in stile Perl condiviso dalla maggior parte dei linguaggi moderni — con una particolarità specifica di Java: ogni backslash in un pattern deve essere raddoppiato in un letterale stringa Java, perché il compilatore ne consuma uno prima che il motore regex lo veda. Questo capitolo è un riferimento a quella sintassi: i mattoni che combini per cercare, trovare corrispondenze e validare testo.
Se sei nuovo alle espressioni regolari in Java, inizia con l'Introduzione alle Regex Java, poi torna qui quando hai bisogno del cheat sheet completo della sintassi.
Letterali e metacaratteri
La maggior parte dei caratteri in un pattern corrispondono a sé stessi: cat corrisponde alle tre lettere c, a, t. La potenza deriva dai metacaratteri — caratteri con significato speciale che combini in regole. I dodici trattati specialmente dal motore sono:
. ^ $ * + ? ( ) [ ] { } | \Per corrispondere a uno di questi letteralmente, eseguine l'escape con un backslash. Ricorda la regola del doppio backslash per il sorgente Java: una regex \. si scrive "\\." nel codice.
Pattern.matches("a.c", "abc"); // true — '.' matches any char
Pattern.matches("a.c", "a.c"); // true — '.' also matches a literal dot
Pattern.matches("a\\.c", "abc"); // false — '\.' matches ONLY a literal dot
Pattern.matches("a\\.c", "a.c"); // trueClassi di caratteri
Una classe di caratteri tra parentesi quadre corrisponde a qualsiasi singolo carattere di un insieme. Gli intervalli usano un trattino, e un ^ iniziale nega l'insieme.
"[aeiou]" // any one lowercase vowel
"[a-z]" // any one lowercase letter
"[A-Za-z0-9]" // any letter or digit
"[^0-9]" // any character that is NOT a digitJava offre anche classi predefinite come abbreviazioni. Quelle che usi costantemente sono:
| Abbreviazione | Equivalente | Corrisponde a |
|---|---|---|
. | — | Qualsiasi carattere tranne un terminatore di riga |
\d | [0-9] | Una cifra |
\D | [^0-9] | Una non-cifra |
\w | [a-zA-Z0-9_] | Un carattere di parola |
\W | [^a-zA-Z0-9_] | Un carattere non di parola |
\s | [ \t\n\x0B\f\r] | Un carattere di spazio bianco |
\S | [^\s] | Un carattere non di spazio bianco |
La forma maiuscola è sempre la negazione della forma minuscola. Vedi Classi di Caratteri Regex Java per l'insieme completo, incluse le classi POSIX e Unicode.
Quantificatori: greedy, reluctant, possessive
Un quantificatore specifica quante volte l'elemento precedente può ripetersi. Per impostazione predefinita i quantificatori sono greedy — prendono quanto più possibile, poi cedono se il resto del pattern lo richiede. Aggiungi ? per rendere un quantificatore reluctant (corrisponde al minimo possibile), o + per renderlo possessive (prende e non restituisce mai).
| Quantificatore | Significato |
|---|---|
* | Zero o più volte |
+ | Una o più volte |
? | Zero o una volta (opzionale) |
{n} | Esattamente n volte |
{n,} | Almeno n volte |
{n,m} | Tra n e m volte |
"\\d{3}" // exactly three digits
"\\d{2,4}" // two to four digits
"a+" // one or more 'a'
"colou?r" // matches "color" and "colour"
"<.+>" // greedy: on "<a><b>" matches the whole "<a><b>"
"<.+?>" // reluctant: on "<a><b>" matches just "<a>"Per un approfondimento sul comportamento greedy, reluctant e possessive, leggi Quantificatori Regex Java.
Ancoraggi, confini e alternanza
Gli ancoraggi corrispondono a una posizione, non a un carattere. ^ è l'inizio dell'input (o della riga, in modalità multiriga), $ è la fine, e \b è un confine di parola — la posizione a larghezza zero tra un \w e un \W. L'alternanza con | corrisponde a uno dei due lati.
"^Hello" // "Hello" only at the start
"\\.txt$" // ".txt" only at the end
"\\bcat\\b" // "cat" as a whole word, not inside "category"
"cat|dog" // "cat" or "dog"
"^(cat|dog)$" // the whole string is exactly "cat" or "dog"Nota che | ha una precedenza molto bassa: ^cat|dog$ significa (^cat)|(dog$), non ^(cat|dog)$. Racchiudi le alternative in un gruppo quando vuoi che gli ancoraggi si applichino a entrambe.
Gruppi, backreference e flag inline
Le parentesi tonde creano un gruppo di cattura — il motore ricorda cosa ciascun gruppo ha catturato, numerato da sinistra a destra a partire da 1. (?:...) è un gruppo non di cattura quando devi solo applicare un quantificatore. Una backreference \1 corrisponde allo stesso testo catturato dal primo gruppo. I flag inline come (?i) cambiano il comportamento di corrispondenza senza un flag separato di Pattern.compile.
"(\\d{4})-(\\d{2})" // group 1 = year, group 2 = month
"(?:ab)+" // repeats "ab" without capturing it
"(\\w+) \\1" // a word followed by itself ("the the")
"(?i)java" // case-insensitive: matches "Java", "JAVA"
"(?m)^line" // multiline: ^ matches at each line startI gruppi di cattura hanno il loro capitolo — Gruppi Regex Java tratta i gruppi con nome e come leggere il testo catturato da un Matcher. I flag inline come (?i) e (?m) sono gli equivalenti nel pattern dei flag di Pattern.compile descritti in Flag Regex Java.
Un esempio pratico: i costrutti in azione
Questo programma utilizza una classe di cifre con un quantificatore, alternanza ancorata, una backreference, corrispondenza greedy versus reluctant, l'abbreviazione \w+ e un flag inline case-insensitive — tutto con java.util.regex soltanto. La sintassi qui guida le API Pattern e Matcher trattate in Java Regex Pattern e Matcher.
Cosa ricavare dall'esecuzione:
\d{4}ha trovato sia1995che2011perchéfind()scansiona ogni corrispondenza nell'input, mentre una classe con quantificatore (\dripetuto{4}volte) è il modo canonico per corrispondere a un campo di larghezza fissa. Il doppio backslash in"\\d{4}"è il letterale stringa Java che produce il singolo backslash che il motore si aspetta.Pattern.matches("cat|dog", "dog")ha restituitotruema lo stesso pattern su"catnap"ha restituitofalse—matches()ancora implicitamente l'intero input, quindi anche secatappare incatnap, ilnapfinale non viene corrisposto e la corrispondenza complessiva fallisce.- La backreference
\1ha trasformato(\w+) \1in "una parola seguita dalla parola identica," motivo per cui ha riportatotheeis— le due ripetizioni — e ha ignorato ogni parola non immediatamente ripetuta. Le backreference corrispondono al testo catturato, non al pattern di nuovo. - Sullo stesso input
<a><b>, il greedy<.+>ha inghiottito l'intera stringa mentre il reluctant<.+?>si è fermato al primo>, producendo solo<a>. Questo singolo contrasto è la correzione di bug regex più comune che farai mai: aggiungi?a un quantificatore quando prende troppo. \w+ha contato 3 token inab, cd-ef!—ab,cdeef— perché,,-e!sono tutti caratteri\W(non di parola) che interrompono una sequenza di caratteri di parola. Il flag inline(?i)ha poi fatto corrisponderejavaconJAVA, mostrando che i flag possono vivere all'interno del pattern stesso anziché solo inPattern.compile.