W3docs

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"); // true

Classi 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 digit

Java offre anche classi predefinite come abbreviazioni. Quelle che usi costantemente sono:

AbbreviazioneEquivalenteCorrisponde 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).

QuantificatoreSignificato
*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 start

I 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.

java— editable, runs on the server

Cosa ricavare dall'esecuzione:

  • \d{4} ha trovato sia 1995 che 2011 perché find() scansiona ogni corrispondenza nell'input, mentre una classe con quantificatore (\d ripetuto {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 restituito true ma lo stesso pattern su "catnap" ha restituito falsematches() ancora implicitamente l'intero input, quindi anche se cat appare in catnap, il nap finale non viene corrisposto e la corrispondenza complessiva fallisce.
  • La backreference \1 ha trasformato (\w+) \1 in "una parola seguita dalla parola identica," motivo per cui ha riportato the e is — 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 in ab, cd-ef!ab, cd e ef — perché ,, - e ! sono tutti caratteri \W (non di parola) che interrompono una sequenza di caratteri di parola. Il flag inline (?i) ha poi fatto corrispondere java con JAVA, mostrando che i flag possono vivere all'interno del pattern stesso anziché solo in Pattern.compile.

Pratica

Pratica
Sull'input '<a><b>', perché la regex '<.+>' corrisponde all'intera stringa '<a><b>' mentre '<.+?>' corrisponde solo a '<a>'?
Sull'input '<a><b>', perché la regex '<.+>' corrisponde all'intera stringa '<a><b>' mentre '<.+?>' corrisponde solo a '<a>'?
Was this page helpful?