Cosa sono le espressioni regolari
Le espressioni regolari (regex o regexp) sono sequenze di caratteri che definiscono un pattern di ricerca. Permettono di cercare, validare, estrarre e sostituire testo con una precisione impossibile con i normali metodi stringa. Sono supportate in tutti i linguaggi di programmazione moderni — JavaScript, Python, Java, PHP, Ruby, Go — con sintassi quasi identica.
Una regex è composta da caratteri letterali (che matchano se stessi) e metacaratteri (che hanno significati speciali). Capire questa distinzione è il primo passo per padroneggiare le regex.
I metacaratteri fondamentali
| Metacarattere | Significato | Esempio |
|---|---|---|
| . | Qualsiasi carattere (tranne newline) | a.c → "abc", "axc" |
| \d | Cifra (0-9) | \d\d → "42", "99" |
| \D | Non cifra | \D+ → "abc", "xy" |
| \w | Carattere parola (a-z, A-Z, 0-9, _) | \w+ → "hello_123" |
| \W | Non carattere parola | \W → " ", "!", "@" |
| \s | Spazio bianco (spazio, tab, newline) | \s+ → " " |
| \S | Non spazio bianco | \S+ → "testo" |
| ^ | Inizio stringa (o riga con flag m) | ^ciao → "ciao mondo" |
| $ | Fine stringa (o riga con flag m) | mondo$ → "ciao mondo" |
| \b | Word boundary | \bcat\b → "cat" ma non "cats" |
| [abc] | Classe di caratteri — uno tra a, b, c | [aeiou] → vocali |
| [^abc] | Negazione classe — nessuno tra a, b, c | [^0-9] → non cifre |
| [a-z] | Intervallo — da a a z | [a-zA-Z] → lettere |
| \ | Escape — usa il carattere letteralmente | \. → punto letterale |
Quantificatori: quante volte deve matchare
| Quantificatore | Significato | Lazy (minimo) |
|---|---|---|
| * | 0 o più volte | *? |
| + | 1 o più volte | +? |
| ? | 0 o 1 volta (opzionale) | ?? |
| {n} | Esattamente n volte | — |
| {n,} | Almeno n volte | {n,}? |
| {n,m} | Da n a m volte | {n,m}? |
Greedy vs Lazy: la differenza pratica
I quantificatori di default sono greedy: catturano il massimo possibile. Aggiungendo ? diventano lazy: catturano il minimo.
Gruppi di cattura e riferimenti
Le parentesi tonde creano gruppi di cattura che puoi estrarre o riutilizzare:
Backreference: riferirsi a un gruppo già catturato
Lookahead e Lookbehind — assertions
Le assertions guardano avanti o indietro senza consumare caratteri — non fanno parte del match ma condizionano cosa viene matchato:
I flag delle regex
| Flag | Nome | Effetto |
|---|---|---|
| g | global | Trova tutti i match (non solo il primo) |
| i | ignoreCase | Case-insensitive: "A" matcha "a" |
| m | multiline | ^ e $ matchano inizio/fine riga |
| s | dotAll | Il punto matcha anche newline (ES2018+) |
| u | unicode | Tratta il pattern come Unicode |
| d | hasIndices | Aggiunge indici start/end ai match (ES2022+) |
15 pattern pronti all'uso
Errori comuni e come evitarli
Il punto matcha tutto
L'errore più frequente dei principianti: usare . quando si vuole matchare un punto letterale. 3.14 come regex matcha "3X14", "3 14", "3.14" — qualsiasi carattere al posto del punto. Usa 3\.14 per il punto letterale.
Catastrophic backtracking
Pattern come (a+)+ o (a|aa)+ su input che non matchano possono impiegare secondi, minuti o bloccare il motore regex. Il motore esplora esponenzialmente tutte le combinazioni possibili prima di arrendersi. Evita: quantificatori annidati sugli stessi caratteri, alternazione di pattern che si sovrappongono.
ReDoS (Regex Denial of Service): i web server che accettano regex da utenti non fidati sono vulnerabili a attacchi ReDoS — input appositamente costruiti che fanno impazzire il motore regex. Valida sempre le regex degli utenti con un timeout o usa un motore regex lineare.
Ancora dimenticata
/\d+/ matcha qualsiasi stringa che contiene almeno una cifra — incluse "abc123" e "x1y". Per validare che l'intera stringa sia composta solo da cifre, usa /^\d+$/ con le ancore ^ e $.
Charset e Unicode
\w in JavaScript senza il flag u copre solo ASCII ([a-zA-Z0-9_]) — non matcha lettere accentate come è, à, ü. Per testo internazionale usa /[\p{L}\p{N}_]+/u con le Unicode property escapes.
Regex in JavaScript: i metodi essenziali
FAQ
Il punto è un metacarattere che matcha qualsiasi carattere tranne il newline. Per matchare un punto letterale, escapalo con backslash: \.. Con il flag s (dotAll), il punto matcha anche il newline.
Greedy (+, *) cattura il massimo possibile. Lazy (+?, *?) cattura il minimo. Su <b>testo</b>, <.+> cattura tutto, <.+?> cattura ogni tag separatamente.
Aggiungi le lettere esplicitamente alla classe: [a-zàèéìíîòóùú]. Oppure usa Unicode property escapes con il flag u: /[\p{L}]+/u matcha qualsiasi lettera Unicode incluse le accentate.
La sintassi di base è quasi identica. Le differenze principali: Python usa re.compile() e re.match()/re.search() invece dei metodi su stringa; i flag hanno nomi diversi (re.IGNORECASE invece di /i); Python supporta i lookbehind di lunghezza variabile con il modulo regex (non il built-in re).
Pattern con quantificatori annidati sugli stessi caratteri (es. (a+)+) possono impiegare tempo esponenziale su input che non matchano — bloccando il browser o il server. Evita pattern ambigui e testa sempre le regex con input che NON devono matchare.