Skip to content

Le espressioni regolari, o RegEx, sono strumenti essenziali per qualsiasi webmaster o sviluppatore, utilizzate per la ricerca e manipolazione di testi basati su pattern specifici. Originariamente definite da Stephen Kleene nel 1950 e implementate per la prima volta da Ken Thompson nel 1966, le RegEx continuano a essere un elemento fondamentale nel lavoro sul web.

Punti chiave:

  • Definizione e Storia: Le espressioni regolari sono state create per filtrare, identificare o confrontare stringhe di testo basandosi su pattern definiti.
  • Applicazioni Pratiche: Utilizzate in vari contesti come Google Analytics, validazione di e-mail, e filtraggio di dati.
  • Sintassi di Base: Comprendono caratteri singoli, caratteri speciali, gruppi di caratteri, e operatori di ripetizione.
  • Utilizzo Avanzato: Include classi di caratteri, ancoraggi per inizio/fine di stringa, e quantificatori.
  • Strumenti di Supporto: Diversi strumenti online e software sono disponibili per testare e costruire espressioni regolari.

La guida che segue esplora in dettaglio le funzionalità, le applicazioni e la sintassi delle espressioni regolari, fornendo esempi pratici e suggerimenti utili se sei un webmaster o un consulente SEO professionista.

Introduzione

Il termine RegEx, in inglese “Regular Expressions” indica una funzione per filtrare, confrontare o identificare stringhe di caratteri o codice.

Le espressioni regolari sono state definite da Stephen Kleene nel 1950 ed implementate per la prima volta da Ken Thompson nell’editor QED, era il 1966. Ancora oggi le RegEx rimangono insostituibili e, per chi lavora nel web, è un plus saperle utilizzare dato che sono presenti in praticamente tutti gli strumenti che utilizziamo.

Stephen Cole Kleene

Le espressioni regolari sono state definite da Stephen Kleene nel 1950 ed implementate per la prima volta da Ken Thompson nell’editor QED, era il 1966. Ancora oggi le RegEx rimangono insostituibili e, per chi lavora nel web, è un plus saperle utilizzare dato che sono presenti in praticamente tutti gli strumenti.

Un esempio di utilizzo pratico delle RegEx potrebbe essere filtrare gruppi di pagine in un report di Google Analytics, oppure creare una regex che redireziona un set di pagine, o ancora validare il formato di una e-mail inserita in un form. Gli indirizzi e-mail infatti devono essere composti in questo modo:

  • una sequenza di caratteri alfanumerici
  • chiocciola
  • altri caratteri alfanumerici
  • punto
  • due o tre lettere

Il modello è rappresentabile attraverso l’utilizzo delle espressioni regolari, qualora fosse codificata secondo una sintassi ben precisa e riconosciuta da un programma in grado di analizzare le stringhe.

La regex per validare una email è la seguente:

^[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$

oppure

^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$

N.B. non esiste una RegEx infallibile per questo particolare task perché le e-mail possono variare molto una dall’altra. Puoi creare espressioni regolari che sono combinazioni di caratteri e meta-caratteri.

Vediamo nel dettaglio caratteristiche e funzionamento delle RegEx.

Esempi con RegEx
Esempi con RegEx

Stringhe semplici

Usare le espressioni regolari per filtrare stringhe semplici è come andare a caccia di mosche con un lanciarazzi. Come vedremo le RegEx permettono di sfruttare specifici operatori per compiti molto complessi, ma possono essere usate anche per necessità molto basilari.

Caratteri singoli

Il filtro più semplice è quello di ricercare un singolo carattere. La RegEx “x” ritrova tutte le x in una frase, sia x singole che inserite in parole.

Caratteri speciali

Un compito leggermente più impegnativo è ricercare caratteri speciali, come ad esempio il simbolo del dollaro $ che, come vedremo, ha una specifica funzione nelle RegEx. Per filtrare un carattere speciale è necessario anteporre il backslash: \$. Questo concetto relativo al backslash lo approfondiamo tra poco.

Stringhe semplici

Per filtrare stringhe semplici basta ripetere la stringa, a meno che non contenga caratteri speciali ai quali andrebbe anteposto il backslash. La stringa, ad esempio “del” filtrerebbe sia la parola singola del sia la stessa sequenza contenuta in altre parole: della.

Caratteri e meta-caratteri

Un carattere è qualsiasi lettera, numero, simbolo e spazio. Nelle RegEx, il loro significato è letterale – la lettera A equivale alla lettera A, il numero 77 equivale al numero 77, e una parola equivale esattamente alla stessa parola, maiuscole e minuscole comprese.

I meta-caratteri invece non sono considerati letteralmente. Ora analizzerò tutti i meta-caratteri utilizzabili nelle RegEx. Se intanto vuoi testare le funzionalità RegEx puoi aprire Google Analytics e giocare con il filtro posto sopra i report. In alternativa puoi usare RegExpal per testare i tuoi esempi.

Punto .

Il punto è il jolly delle RegEx e, come nelle carte, rappresenta qualsiasi carattere singolo, quindi qualsiasi lettera, numero, simbolo o spazio. Ad esempio l’espressione regolare .etto rappresenta le stringhe petto, netto, detto, setto, !etto, etc, … Il termine “etto” non sarà incluso nella corrispondenza perché il punto richiede comunque la presenza di un carattere.

Una RegEx, se non specificato, può filtrare parole singole o parti di parole. Ad esempio “.etto” filtrerebbe anche “corretto” e non solo parole di 4 lettere. La RegEx corretta per filtrare solo parole di 4 lettere sarebbe: “\b.etto\b”. Più avanti vedremo come delimitare l’inizio o la fine di una parola con il carattere semplice \b.

Backslash \

Nelle espressioni regolari, il backslash () ha la funzione di indicare che il metacarattere successivo deve essere considerato come un carattere semplice, ovvero un carattere letterale. Il backslash viene utilizzato per “sfuggire” ai metacaratteri, in modo che possano essere interpretati come caratteri letterali piuttosto che come simboli speciali all’interno dell’espressione regolare.

Vediamo un paio di esempi.

Spesso capita di dover confrontare stringhe di testo con meta-caratteri. Per filtrare un IP 192.168.1.123, la RegEx giusta potrebbe essere 192.168.1.123 – tuttavia questa stringa corrisponde anche a 192116811123 dato che i punti possono rappresentare qualsiasi carattere. In questo caso quindi il punto va interpretato come tale (meta carattere) e non come variabile della RegEx.

Il backslash (\) definisce quindi che il prossimo carattere va interpretato come carattere semplice e non come meta carattere. Il punto che segue normalmente in una RegEx vorrebbe dire “un carattere qualsiasi”, ma in questo caso significa “un punto”. Quindi lo interpretiamo come un punto letterale.

Precedere un meta-carattere con un backslash si indica che il meta-carattere deve essere considerato come carattere e trattato letteralmente. In questo esempio dovresti usare:

192\.168\.1\.123

Backslash e caratteri normali

Vediamo l’esempio opposto. Per filtrare da una frase la parola “barba” posso usare l’espressione regolare \bbarba\b – Il carattere “b” preceduto da “\” corrisponde agli spazi bianchi prima o dopo le parole. Esistono molti caratteri che, se preceduti da backslash, possono assumere un significato speciale. Vediamo l’elenco completo:

\A - Inizio del testo. 
\a - Codice Bell (segnale acustico). 
\b - Bordo di una parola. 
\B - Tutto tranne \b. 
\c - Codice di controllo (Ctrl). \d - Cifra. 
\D - Tutto tranne \d. 
\e - Codice di "escape". 
\f - Codice di fine pagina. 
\n - Codice di fine riga. 
\r - Codice di ritorno carrello. 
\s - Spazio. 
\S - Tutto tranne \s. 
\t - Codice di tabulazione. 
\uHHHH - Codice di un carattere Unicode. 
\v - Codice di tabulazione verticale. 
\w - Carattere di una parola. 
\W - Tutto tranne \w. 
\xHH - Codice di un carattere ASCII. 
\Z - Fine del testo. 

Per filtrare la parola “se” in questa frase: “Dopo sposto la sedia se mi alzo”. Con la RegEx “se” filtrerei due elementi: “Dopo sposto la sedia se mi alzo”. Invece con la RegEx \bse\b filtrerei solo la singola parola “se”: “Dopo sposto la sedia se mi alzo”.

Backslash e caratteri speciali

Come abbiamo visto, backslash ha una duplice funzione: rende speciali i caratteri normali (esempio della barba) e rende normali i caratteri speciali (esempio dell’IP). Il motivo è che nelle espressioni regolari esistono alcuni caratteri speciali che hanno specifici significati, ma quei caratteri potrebbero essere presenti come lettere normali all’interno di un testo. Quindi come riconoscerli? Anteponendo appunto il backslash.

I caratteri speciali delle RegEx sono:

^ - Inizio della stringa/riga. 
$ - Fine della stringa/riga. 

Operatori di ripetizione

* - Seleziona 0 o più occorrenze del precedente elemento {0,}.
+ - Seleziona 1 o più occorrenza del precedente elemento {1,}.
? - Seleziona 0 oppure 1 occorrenza del precedente elemento {0,1}.
. - Qualsiasi carattere tranne \n.
{n,m} - Numero di ripetizioni. Seleziona il precedente elemento almeno n-volte ma non più di m-volte.
{n,} - Numero di ripetizioni. Seleziona il precedente elemento n-volte o più.
{n} - Seleziona esattamente n-volte il precedente elemento.

Operatori di Gruppo

[abc] - Un singolo carattere: a, b, oppure c
[^abc] - Qualsiasi carattere singolo tranne a, b, oppure c
[a-z] - Qualsiasi carattere nel range a-z
[a-zA-Z] - Qualsiasi carattere nel range a-z oppure A-Z (qualsiasi carattere alfabetico)
| - Alternativa: rappresenta entrambe le espressioni a sinistra e a destra di |
() - Gruppo, raggruppa gli operatori di ripetizione

Cosa fare per filtrare un backslash \? Semplice, basta anteporre un backslash: “\\” così non verrà considerato un carattere speciale ma “puntuale”.

Per filtrare “6*6=36” sarebbe errato riscrivere i caratteri tali e quali poiché una RegEx di quel tipo vorrebbe dire “cerca “6=36” seguito da 6 ripetuto zero o più volte. L’espressione corretta è “6\*6=36”.

Tabella: significato dei caratteri speciali

CarattereSignificatoEsempio
*corrisponde a zero, uno o più del carattere precedenteAh* corrisponde a Ahhhhh o A
?corrisponde a zero o uno del carattere precedenteAh? corrisponde a A o Ah
+corrisponde a uno o più del carattere precedenteAh+ corrisponde a Ah o Ahhh ma non “A
\Usato per escludere un carattere specialeHungry\? corrisponde a Hungry?
.Wildcard, carattere jolly, corrisponde a qualsiasi caratteredo.* corrisponde a dog door dot etc.
( )Gruppo di caratteriVedi ad esempio |
[ ]corrisponde ad un range di caratteri [cbf]ar corrisponde a “car”, “bar”, o “far” [0-9]+ corrisponde a qualsiasi numero intero positivo tra 0 e 9 inclusi [a-zA-Z] corrisponde a lettere ASCII a-z (maiuscole e minuscole) [^0-9] corrisponde a qualsiasi carattere non numerico
|corrisponde ae previous OR next carattere/group(Mon)|(Tues)day corrisponde a Monday o Tuesday
{ }corrisponde a specified number of occurrences del carattere precedente [0-9]{3} corrisponde a 315 ma non 31 [0-9]{2,4} corrisponde a 12 123 e 1234 [0-9]{2,} corrisponde a 1234567...
^Inizio di una stringa oppure per negare una classe di caratteri [].^http corrisponde a stringhe che iniziano con http, come ad esempio un URL. [^0-9] corrisponde a qualsiasi carattere not 0-9.
$End of a string.ing$ corrisponde a exciting ma non ingenious

Punto interrogativo – ?

Il punto interrogativo si trova spesso in URL dinamici, come ad esempio /category.php?catid=23. Se vuoi tracciare questa pagina come parte del percorso di conversione, potresti trovare delle difficoltà nel rappresentare il punto interrogativo perché è considerato un meta-carattere.

La soluzione è semplice, basta infatti usare il backslash in questo modo: /category.php\?catid=23

Parentesi quadre e classi di caratteri []

Insiemi di caratteri []

Le parentesi quadre vengono utilizzate per definire un set di caratteri e si possono utilizzare in due modi: affiancando i caratteri [XY] oppure dividendoli con il meno [0-9]. Qualsiasi carattere compreso nelle parentesi può essere confrontato.

Nel primo caso [XY], ad esempio, il primo carattere è una parentesi quadra aperta e quindi quello che segue è la definizione di una classe di caratteri, segue la RegEx [Gg]iovanni che filtra sia il termine Giovanni che giovanni. La parentesi quadra chiusa termina la definizione della classe.

Sequenze di caratteri [-]

Nel secondo caso [1-9] il primo termine è uno o zero che ci dice che la classe contiene quel carattere. Il – ci dice che stiamo componendo un range di caratteri e il 9 è il carattere di chiusura del range.

Abbiamo visto che all’interno delle parentesi quadre si possono anche usare degli intervalli, definiti con il trattino meno “-“. Ad esempio [0-9] combina qualsiasi numero da 1 a 9, oppure [a-z] combina tutte le lettere minuscole dell’alfabeto. E’ anche possibile combinare intervalli, come ad esempio [A-Fa-f] per confrontare qualsiasi lettera compresa tra “a” ed “f” sia maiuscola che minuscola.

Tabella: significato delle classi di caratteri POSIX

POSIX o “Portable Operating System Interface per uniX” è una raccolta di standard che definiscono alcune delle funzionalità che un sistema operativo (UNIX) dovrebbe supportare. Uno di questi standard definisce due modelli di espressioni regolari. I comandi che coinvolgono espressioni regolari, come grep ed egrep, implementano questi modelli su sistemi UNIX conformi a POSIX. Diversi sistemi di database utilizzano anche le espressioni regolari POSIX.

Le espressioni regolari di base – BRE standardizzano funzioni simili a quelle utilizzate dal comando grep UNIX tradizionale. Una cosa che distingue questa funzione è che la maggior parte dei metacaratteri richiede una barra rovesciata \ backslash per conferire al metacarattere la sua funzione. POSIX ERE (Extended Regular Expression), utilizza una barra rovesciata per sopprimere il significato dei metacaratteri. L’uso di una barra rovesciata per uscire annullare un carattere che non è mai un metacarattere è un errore.

Una BRE supporta le espressioni di parentesi POSIX, che sono simili alle classi di caratteri RegEx, con alcune caratteristiche speciali. Le stenografie non sono supportate. Altre caratteristiche che usano i soliti metacaratteri sono il punto per abbinare qualsiasi carattere eccetto un’interruzione di riga, il segno di omissione e il dollaro per abbinare l’inizio e la fine della stringa e la stella per ripetere il token zero o più volte. Per abbinare letteralmente qualcuno di questi caratteri speciali devi anteporre la barra rovesciata.

POSIX BRE non supporta altre funzionalità. Anche l’alternanza non è supportata.

Le espressioni regolari estese dette anche ERE standardizzano alcune funzioni simile a quelle utilizzate dal comando egrep UNIX. “Estese” è relativo al grep UNIX originale, che aveva solo espressioni con parentesi, punto, segno di omissione, dollaro e stella. Una ERE li supporta proprio come una BRE (Basic Regular Expression).

Gli sviluppatori di egrep non hanno provato a mantenere la compatibilità con grep, creando invece uno strumento separato. Quindi egrep e POSIX ERE aggiungono metacaratteri aggiuntivi senza backslash. Puoi usare i backslash per sopprimere il significato di tutti i metacaratteri, proprio come nelle RegEx moderne. L’escape di un carattere che non è un metacarattere è un errore.

Classe di carattereSignificato
[:alpha:]Qualsiasi lettera, [A-Za-z]
[:upper:]Qualsiasi lettera maiuscola, [A-Z]
[:lower:]Qualsiasi lettera minuscola, [a-z]
[:digit:]Qualsiasi numero, [0-9]
[:alnum:]Qualsiasi carattere alfanumerico, [A-Za-z0-9]
[:xdigit:]Qualsiasi numero esadecimale, [0-9A-Fa-f]
[:space:]Una scheda, una nuova riga, una scheda verticale, un feed di moduli, carriage return, o spazio
[:blank:]Uno spazio o una scheda
[:print:]Qualsiasi carattere stampabile
[:punct:]Qualsiasi carattere di punteggiatura: ! ' # S % & ' ( ) * + , - . / : ; < = > ? @ [ / ] ^ _ { | } ~
[:graph:]Qualsiasi carattere definito come un carattere stampabile tranne quelli definiti come parte della classe di caratteri spaziali
[:word:]Stringa continua di caratteri alfanumerici e underscore (trattino basso)
[:ascii:]Caratteri ASCII nel range: 0-127
[:cntrl:]Qualsiasi carattere non parte delle classi di caratteri: [:upper:], [:lower:], [:alpha:], [:digit:], [:punct:], [:graph:], [:print:], [:xdigit:]

Accento circonflesso ^

Per escludere dei caratteri si utilizza il simbolo circonflesso “^”. Ad esempio [^0-9] confronta tutto tranne i caratteri nell’intervallo.

Ripetizioni ? + * .* {}

  • Il punto interrogativo, detto anche operatore di ripetizione, seguito da simboli, asterisco e parentesi ti permette di specificare quante volte, zero o più, il precedente carattere o meta-carattere deve ripetersi. Il punto interrogativo è usato per indicare che sia nessuno oppure uno dei precedenti caratteri devono essere confrontati. Questo significa che l’espressione abc? filtrerebbe sia “ab” che “abc, ma non “abcd” o “abcc”.
  • Il simbolo “+” impone che uno o più di uno dei precedenti caratteri deve essere confrontato. Ad esempio abc+ confronta “abc”, “abcc” e anche “abccccccc”. Non filtra invece “ab” poichè il carattere deve essere presente.
  • L’asterisco “*” è un mix tra “?” e “+”. L’asterisco confronta 0, uno o più dei precedenti caratteri. Ad esempio, la RegEx abc* filtra “ab”, “abc”, “abcc”, e tutto ciò che segue come “abccccccc”. L’asterisco ci dice “zero o più di quello che mi precede”.
  • Punto + Asterisco .* rappresenta una combinazione molto potente delle espressioni regolari. Questa regola definisce zero o più caratteri casuali, in altre parole rappresenta qualsiasi sequenza di caratteri, vediamo un esempio che vale mille parole. Mettiamo che il nostro sito ha le cartelle /prodotti/donna/guanti/, /prodotti/uomo/guanti/ e /prodotti/bambino/guanti/. Per filtrare (su Google Analytics ad esempio) tutte le cartelle guanti a prescindere dalla categoria madre possiamo usare l’espressione regolare /prodotti/.*/guanti/
  • Infine le parentesi graffe possono essere usate per definire un numero specifico oppure un intervallo di ripetizioni. La RegEx [0-9]{2} filtrerebbe qualsiasi numero a 2 cifre, metre [a-z]{4,6} filtrerebbe qualsiasi combinazione di lettere minuscole di lunghezza tra i 4 e i 6 caratteri, es: “aaaa”, “bbbbb”, “asdfgh”, ….

Raggruppamenti () |

Le parentesi tonde ti permettono di raggruppare assieme caratteri. Ad esempio potrebbe servirmi un filtro per cercare tutte le parole chiave contenenti il mio nome, e io voglio filtrare sia il testo “giovanni sacheli” che “gio sacheli”. Posso ottenere il risultato con questa RegEx gio(vanni)? sacheli, il punto interrogativo e le parentesi significano che la stringa “vanni” può essere confrontata zero o più volte. In aggiunta puoi utilizzare la “barra verticale” | per rappresentare la funzione “OR” (oppure). Ad esempio la RegEx (eve|EVE)(milano|Milano) traccia i termini “evemilano”, “EVEmilano”, “eveMilano” e “EVEMilano”. La barra verticale può essere usata anche senza parentesi se non hai bisogno di raggruppare caratteri. Ad esempio la RegEx iphone|ipad può essere usata per filtrare il traffico proveniente da entrambe le parole.

Cifre e spazi

Potrebbe servire filtrare delle cifre all’interno di un testo, magari in specifiche posizioni. In altri casi potrebbe servire trovare tutti i caratteri tranne le cifre. Per queste operazioni possiamo usare i comandi “\d” (insieme delle dieci cifre decimali) e “\D” (insieme complementare, tutti i caratteri tranne le 10 cifre).

Per filtrare una data in questo formato 07/02/1980 possiamo usare questo comando: “\d\d/\d\d/\d\d\d\d” (senza virgolette “, in questa guida le uso solo per evidenziare le formula ma non vanno usate come RegEx).

Nelle espressioni regolari esiste un comando per filtrare i soli spazi, ovvero i caratteri vuoti, il comando è “\s”. Il comando complementare, quindi tutto tranne gli spazi, è con la s maiuscola: “\S”.

Ancore ^ $ per definire inizio e fine della stringa

Sebbene avessimo già visto il carattere circonflesso utilizzato con le parentesi quadre, questo simbolo può essere usato anche per definire che la stringa deve iniziare con i seguenti caratteri. Ad esempio se vuoi identificare tutti gli URL di una cartella specifica del tuo sito puoi usare ^prodotti/. Questa RegEx confronta URL del tipo prodotti/item1 e prodotti/item2/etc, ma non URL che non iniziano con la stringa definita, come ../supporto/prodotti/.

Il simbolo del dollaro serve per definire che la stringa deve finire con questi caratteri. Ad esmepio potresti voler filtrare tutti gli URL che terminano con /checkout utilizzando la RegEx /checkout$ che confronterebbe URL come “widgets/cart/checkout” e “gadgets/cart/checkout” ma non “checkout/help”.

Le RegEx usate con Google Analytics

Come ben sappiamo i filtri di Google Analytics possono essere usati per escludere dai report il traffico interno (all’azienda o al network ad esempio) e, in combinazione con le espressioni RegEx possono filtrare qualsiasi range di IP con una sola stringa.

Nelle impostazioni del profilo di Google Analytics, crea un nuovo filtro customizzato che escluda l’IP aziendale nel campo “Visitor IP Address”. Utilizzando una RegEx del tipo 192\.168\.1\.1[123] si andranno ad escludere gli indirizzi IP 192.168.1.11, 192.168.1.12 e 192.168.1.13. Giocando con le regole sopra descritte potrai rappresentare qualsiasi IP.

Un’altra funzione utile di Google Analytics che può trarre molti vantaggi dall’utilizzo delle espressioni regolari sono i segmenti avanzati. I segmenti avanzati possono essere usati per segmentare le parole chiave non legate al brand così da poter analizzare nello specifico i risultati di attività SEO specifiche.

Per ottenere questi filtri crea un segmento avanzato dove il “medium” deve corrispondere esattamente ad “organic” e come regola successiva aggiungi la RegEx per escludere i termini brand. Ad esempio nel mio profilo ho inserito con filtro “escludi” la RegEx:

[Ee]ve\s?[Mm]ilano

che rappresenta tutti i possibili modi di scrittura possibili del brand (nel limite del ragionevole!).

La stessa cosa con filtro “includi” se vuoi filtrare solo le parole chiave brand:

Filtrare parole brand con RegEx in Analytics
Filtrare parole brand con RegEx in Analytics

Per filtrare tutte le ricerche a nome mio invece uso l’espressione regolare:

^[Gg]i[oò](vanni)?|^[Ss]acheli|[Gg]i[oò](vanni)?\s?[Ss]acheli|[Ss]acheli\s?[Gg]i[oò](vanni)?

Si possono usare i segmenti avanzati anche per filtrare il traffico proveniente dai social network. Nel campo “source” imposta l’espressione regolare del tipo facebook|twitter|youtube|digg etc.

Le espressioni RegEx sono utili anche per impostare i Goals e i vari step nel funnel di conversione. Quando imposti il nuovo Goal come URL di destinazione, usa le espressioni regolari per definire le regole. Ad esempio potresti usare la regola ^/(widgets|gadgets)/checkout/thanks\.php$ per tracciare sia/widgets/checkout/thanks.php e sia /gadgets/checkout/thanks.php. Quando imposti un funnel, tutti gli URl sono trattati come espressioni regolari quindi puoi utilizzare la stessa tecnica.

URL Rewriting

Mi aspetto che la maggior parte di voi abbia familiarità con gli URL SEO friendly. Gli URL dovrebbero essere statici invece che dinamici e dovrebbero essere anche descrittivi. Spesso questa ottimizzazione è raggiunta con la tecnica dell’URL Rewriting, disponibile su web server Apache tramite il modulo chiamato mod_rewrite. Le regole sono inserite in un file di testo chiamato .htaccess e posizionato nella root del web server. Una semplice regola di rewrite per escludere la categoria dell’URL può essere:

RewriteEngine On
RewriteRule ^categoria/ricette-veloci/?$ categoria.php?cat=ricette-veloci [NC]

Questo esempio significa che l’URL www.esempio.it/categoria/ricette-veloci/ dovrebbe attualmente servire la pagina www.esempio.it/categoria.php?cat=ricette-veloci. Come menzionato nelle regole ad inizio articolo, il carattere circonflesso e il dollaro ($) significano che l’URL deve iniziare e finire con ricette-veloci/, e il punto interrogativo significa che lo slash finale è opzionale. Il termine [NC] non fa parte delle espressioni regolari ma è parte della sintassi del mod_rewrite e significa che la regola di rewrite non è case sensitive, ovvero ignora se un carattere è minuscolo o maiuscolo.

Ovviamente questo approccio non è consigliato per grandi siti con migliaia di URL, è proprio in questo caso che le espressioni regolari RegEx tornano particolarmente utili perché è possibile definire un pattern o regole più generali. Una regola di rewrite dinamica che utilizza le RegEx è ad esempio:

RewriteEngine On
RewriteRule ^categoria/([A-Za-z0-9-]+)/?$ categoria.php?cat=$1 [NC]

Questa regola imposta che l’URL deve cominciare con categoria/ e che può essere seguito da qualsiasi combinazione di lettere, numeri o simboli fino a quando non ci sono uno o più “+”. Questa parte della regola è racchiusa tra parentesi così che possa fare riferimento nella seconda parte della regola con l’espressione $1. Se hai un set successivo di parentesi ci si può riferire ad esso con $2 e così via. Dato che lo slash finale è opzionale si pone il punto interrogativo, mentre l’accento circonflesso e il dollaro ($) definiscono l’inizio e la fine dell’URL.

Infografica su RegEx e mod_rewrite

RegEx nel mod_rewrite di Apache
RegEx nel mod_rewrite di Apache

Costrutti nella Espressioni Regolari

Characters
x	The character x
\\	The backslash character
\0n	The character with octal value 0n (0 <= n <= 7)
\0nn	The character with octal value 0nn (0 <= n <= 7)
\0mnn	The character with octal value 0mnn (0 <= m <= 3, 0 <= n <= 7)
\xhh	The character with hexadecimal value 0xhh
\uhhhh	The character with hexadecimal value 0xhhhh
\t	The tab character ('\u0009')
\n	The newline (line feed) character ('\u000A')
\r	The carriage-return character ('\u000D')
\f	The form-feed character ('\u000C')
\a	The alert (bell) character ('\u0007')
\e	The escape character ('\u001B')
\cx	The control character corresponding to x
 
Character classes
[abc]	a, b, or c (simple class)
[^abc]	Any character except a, b, or c (negation)
[a-zA-Z]	a through z or A through Z, inclusive (range)
[a-d[m-p]]	a through d, or m through p: [a-dm-p] (union)
[a-z&&[def]]	d, e, or f (intersection)
[a-z&&[^bc]]	a through z, except for b and c: [ad-z] (subtraction)
[a-z&&[^m-p]]	a through z, and not m through p: [a-lq-z](subtraction)
 
Predefined character classes
.	Any character (may or may not match line terminators)
\d	A digit: [0-9]
\D	A non-digit: [^0-9]
\s	A whitespace character: [ \t\n\x0B\f\r]
\S	A non-whitespace character: [^\s]
\w	A word character: [a-zA-Z_0-9]
\W	A non-word character: [^\w]
 
POSIX character classes (US-ASCII only)
\p{Lower}	A lower-case alphabetic character: [a-z]
\p{Upper}	An upper-case alphabetic character:[A-Z]
\p{ASCII}	All ASCII:[\x00-\x7F]
\p{Alpha}	An alphabetic character:[\p{Lower}\p{Upper}]
\p{Digit}	A decimal digit: [0-9]
\p{Alnum}	An alphanumeric character:[\p{Alpha}\p{Digit}]
\p{Punct}	Punctuation: One of !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Graph}	A visible character: [\p{Alnum}\p{Punct}]
\p{Print}	A printable character: [\p{Graph}\x20]
\p{Blank}	A space or a tab: [ \t]
\p{Cntrl}	A control character: [\x00-\x1F\x7F]
\p{XDigit}	A hexadecimal digit: [0-9a-fA-F]
\p{Space}	A whitespace character: [ \t\n\x0B\f\r]
 
java.lang.Character classes (simple java character type)
\p{javaLowerCase}	Equivalent to java.lang.Character.isLowerCase()
\p{javaUpperCase}	Equivalent to java.lang.Character.isUpperCase()
\p{javaWhitespace}	Equivalent to java.lang.Character.isWhitespace()
\p{javaMirrored}	Equivalent to java.lang.Character.isMirrored()
 
Classes for Unicode blocks and categories
\p{InGreek}	A character in the Greek block (simple block)
\p{Lu}	An uppercase letter (simple category)
\p{Sc}	A currency symbol
\P{InGreek}	Any character except one in the Greek block (negation)
[\p{L}&&[^\p{Lu}]] 	Any letter except an uppercase letter (subtraction)
 
Boundary matchers
^	The beginning of a line
$	The end of a line
\b	A word boundary
\B	A non-word boundary
\A	The beginning of the input
\G	The end of the previous match
\Z	The end of the input but for the final terminator, if any
\z	The end of the input
 
Greedy quantifiers
X?	X, once or not at all
X*	X, zero or more times
X+	X, one or more times
X{n}	X, exactly n times
X{n,}	X, at least n times
X{n,m}	X, at least n but not more than m times
 
Reluctant quantifiers
X??	X, once or not at all
X*?	X, zero or more times
X+?	X, one or more times
X{n}?	X, exactly n times
X{n,}?	X, at least n times
X{n,m}?	X, at least n but not more than m times
 
Possessive quantifiers
X?+	X, once or not at all
X*+	X, zero or more times
X++	X, one or more times
X{n}+	X, exactly n times
X{n,}+	X, at least n times
X{n,m}+	X, at least n but not more than m times
 
Logical operators
XY	X followed by Y
X|Y	Either X or Y
(X)	X, as a capturing group
 
Back references
\n	Whatever the nth capturing group matched
 
Quotation
\	Nothing, but quotes the following character
\Q	Nothing, but quotes all characters until \E
\E	Nothing, but ends quoting started by \Q
 
Special constructs (non-capturing)
(?:X)	X, as a non-capturing group
(?idmsux-idmsux) 	Nothing, but turns match flags i d m s u x on - off
(?idmsux-idmsux:X)  	X, as a non-capturing group with the given flags i d m s u x on - off
(?=X)	X, via zero-width positive lookahead
(?!X)	X, via zero-width negative lookahead
(?<=X)	X, via zero-width positive lookbehind
(?<!X)	X, via zero-width negative lookbehind
(?>X)	X, as an independent, non-capturing group

Regole utili per Find and Replace

#Selezione tag immagini
<img([\w\W]+?)/>

#Selezione headings
(?s)<h1>.+</h1>

#Selezione div tag
</?\bdiv\b[^>]*>

#Selezione p tag
<p>(.+?)</p>

#Selezione parentesi quadre
\[(.*?)\]

#Selezione parentesi tonde
\(([^\)]+)\)

#Selezione linee bianche
\r\n

Strumenti e approfondimenti

Autore

Commenti |18

Lascia un commento Lascia un commento
  1. ele 1 commento

    Ciao, se dovessi fare un redirect di decine di URL con questa struttura, che regola dovrei usare?
    http://www.sito.it/notizie.asp?action=vis_news&NewsID=68
    http://www.sito.it/notizie.asp?action=vis_news&NewsID=74

    RewriteRule ^notizie.asp^?$ http://www.sito.it/ [R=301,L] http://www.sito.it/news

  2. Giovanni Sacheli 754 risposte

    Ciao Ele, considera che è sempre meglio fare redirect 1-to1 ed evitare quindi di rimandare tante pagine alla home. Mantenendo l’ID anche nel redirect la regola potrebbe essere una cosa del genere:

    RewriteCond %{QUERY_STRING} ^action=vis_news&NewsID=68$ [NC]
    RewriteRule ^notizie\.asp$ http://www.sito.it/news.asp?ID=68 [R=301,NE,NC,L]

  3. Biondo 2 commenti

    Ciao Giovanni,

    eccellente articolo. Vorrei chiederti un suggerimento…
    Hai detto che alcune regole non sono consigliate per grandi siti, ebbene, per un multisito wordpress sottodirectory con molto traffico come posso, nel migliore dei modi, riscrivere l’indirizzo da
    nomesito.com/it-it/ *quello che segue
    nomesito.com/fr-fr/ *quello che segue
    nomesito.com/de-de/ *quello che segue
    a
    it.it.nomesito.com/ *quello che segue
    fr.fr.nomesito.com/ *quello che segue
    de.de.nomesito.com/ *quello che segue

    Ovviamente i sotto domini saranno precedentemente attivati
    Grazie per il cortese suggerimento.

    PS Aggiungo che non voglio fare il passaggio da multisito sottodirectory a sotto dominio perché voglio solo riscrivere i siti di lingua nomesito.com/it-it e non nomesito.com/altro, questi ultimi mi vanno bene così.

    1. Giovanni Sacheli 1 risposte

      Ciao Biondo, quasi tutti gli hosting con cPanel ti permettono di creare sottodomini e farli puntare a sottodirectory. Se non hai questa funzione la cosa è un pelo più complessa perchè dovresti far puntare il sottodominio verso il tuo IP e configurare i Virtual Host (cosa fattibile su Hosting dedicati ma non sempre fattibile su VPS).

      Per redirezionare la richieste di example.com/blog verso blog.example.com, prova questo redirect:

      RewriteEngine on

      RewriteCond %{HTTP_HOST} ^(www\.)?example\.com$
      RewriteRule ^blog/(.*)$ http://blog.example.com/$1 [L,QSA,R=301]

      RewriteCond %{HTTP_HOST} ^blog\.example\.com$
      RewriteCond %{REQUEST_URI} !^blog/
      RewriteRule ^(.*)$ /blog/$1 [L,QSA]

      Una seconda possibilità è mostrata da questa breve guida

  4. Biondo 2 commenti

    Grazie per la celerissima risposta.

    Sì, posso farlo con cPanel ma poi l’indirizzo sarebbe accessibile sia da sottodomini che da sotto cartella, con lo stesso contenuto, e a Google questo non piace molto e a me interessa invece che piaccia. :)
    Ecco il perché vorrei risolvere in modo tale da non rendere accessibile il sito dalle sotto cartelle.
    Sei stato gentilissimo.

  5. ele 1 commento

    Ciao, per bloccare siti di spam con url contenenti trattino – è necessario mettere il backslash davanti?
    Cioè quale delle soluzioni è corretta?

    RewriteEngine on
    RewriteCond %{HTTP_REFERER} buttons\-for\-website\.com [NC,OR]
    RewriteCond %{HTTP_REFERER} semalt\.com [NC]
    RewriteRule .* – [F,L]

    RewriteEngine on
    RewriteCond %{HTTP_REFERER} buttons-for-website\.com [NC,OR]
    RewriteCond %{HTTP_REFERER} semalt\.com [NC]

    1. Giovanni Sacheli 754 risposte

      Ciao Ele, Semalt è davvero fastidioso :)
      La versione corretta è la prima che hai postato:

      # blocco referral semalt.com
      RewriteEngine on
      RewriteCond %{HTTP_REFERER} semalt\.com [NC]
      RewriteRule .* – [F]

  6. Andrea Paoli 1 commento

    Ciao Giovanni, scusa se disturbo ma sto impazzendo da un’ora per trovare la giusta espressione regolare per settare una conversione in analytics.

    Url da evitare: /book/view/t/e294616c0aa89e21c5936f9201f58c2a/pay/gp
    Url da includere: /book/view/t/f3477f7f5a5a4b593b7ecefb4630ae24

    Praticamente tutte le url che iniziano con /book/view/t ma che non hanno nella url pay/gp
    Ho letto anche le tue guide ma mi manca un passaggio…non trovo il modo di fare AND
    Tipo… (book/view/t) AND (^((?!pay/gp).)*$)

    1. Giovanni Sacheli 754 risposte

      Ciao Andrea, grazie per la domanda tecnica :)

      L’espressione regolare che seleziona solo gli URL che finiscono con la serie numerica di 32 caratteri potrebbe essere questa:

      \/book\/view\/t\/[a-zA-Z0-9]{32}$

  7. Beatrice 2 commenti

    Ciao Giovanni, grazie per questo articolo molto chiaro ed esplicativo, volevo chiederti se potrei usare una regex per individuare i nomi ITALIANI in un elenco di nomi MISTI (stranieri ED italiani). Non è un elenco immenso, un po’ meno di 2000 nomi, e credo che per —quantomeno— restringere un po’ il campo andrebbe bene filtrare tutti i nomi senza lettere straniere (xkjwy) e richiedere che ciascuna delle due parole (Cognome, Nome) terminino necessariamente con una vocale. Sei d’accordo con queste regole minime per considerare un nome “italiano”? Sono alle primissime armi in questo frangente , ho già provato a creare qualche regex per trovare nomi italiani come descritto su e ci sono arrivata vicina (purtroppo non la trovo più), ma non ho mai “centrato” l’obiettivo. Perché non esistono elenchi di regex già pronti per l’uso?

    1. Beatrice 2 commenti

      Ci ho riprovato, grazie a un editor esplicativo, trovandone di nuovo una che sembra valida, ma non “del tutto” (purtroppo qualcosa ancora viene filtrato- non riesco forse a fargli intendere questa formula —Cognome, Nome— come un’unica entità, perché a volte nel filtraggio si allaccia alla parola successiva che però appartiene a un altro nome e da lì diventa complicato ) :
      [A-Za-z][^jkxwy]+[aeiou]\b\,\s[A-Za-z][^jkxwy]+[aeiou]\b

      Ho anche provato questa
      [^jkxwy]{2,}[aeiou]\b\,\s[a-zA-Z][^jkxwy]{2,}[aeiou]\b$

    2. Giovanni Sacheli 754 risposte

      Ciao Beatrice, dipende dove devi fare questa operazione. Online oppure offline?
      Offline non userei le Regex per questo compito. Ti consiglio di partire scaricando un database di nomi italiani (su Google ne trovi diversi) e usare Excel con VLOOKUP per taggare al volo i nomi italiani nella tua lista.
      Mi sembra l’approccio più rapido.
      Farlo invece online con Regex mi sembra abbastanza complicato date tutte le varianti possibili (“Loris” ad esempio, è un nome italiano ma non lo troverebbe la tua regex).

  8. Alessandro 3 commenti

    Ciao Giovanni. Ottimo e chiaro ( ma sono io che probabilmente non riesco a capire bene!! )
    Stavo provando ad eseguire una url_regex all’interno di SquidGuard ( squid ) per eseguire questa funzione:
    se la chiamata include /.well-known/ ok ( pass ) altrimenti ko ( denied ).
    Esempio chiamata: https://www.sito.it/path/.well-known/path
    Le regular expression che mi è uscita è:
    (^https?:\/\/[^\s”‘&?]+\/[.]well-known\/[^\s”‘]*)
    in regex101.com viene validato ma su squid no. E’ pure vero che regex101 valida in PCRE mantre squid legge ERE ( GNUregex ). Mi daresti una mano a capire dove sbaglio ?

    1. Giovanni Sacheli 754 risposte

      Ciao Alessandro,
      Hai ragione, SquidGuard utilizza le espressioni regolari Extended (ERE) e non PCRE (Perl Compatible Regular Expressions). Questo significa che alcune funzionalità come il look ahead e il look behind, o il carattere \s per gli spazi bianchi, non sono supportate.
      Inoltre, in SquidGuard, l’inizio e la fine dell’URL non devono essere esplicitamente indicati nell’espressioni regolare. SquidGuard applica l’espressione regolare a qualsiasi parte dell’URL.
      Potresti provare con la seguente espressione regolare:

      (^https?:\/\/[^"'&?]+\/\.well-known\/[^"'&]*)

      In questa espressione regolare, ho rimosso l’uso di \s (dato che non è supportato da ERE) e ho sostituito [.] con \. per corrispondere al carattere ‘.’ letterale.
      Se questa espressione regolare non funziona come previsto, potrebbe essere utile avere un esempio dell’URL che stai cercando di bloccare e un esempio dell’URL che stai cercando di consentire, così da poter affinare l’espressione regolare.

      1. alessandro 3 commenti

        Grazie Giovanni,

        si infatti non va….
        Allora nel mio caso il server che sta dietro Squid ha tutto bloccato.
        Ho creato un allow list nella quale ho inserito solo un sito pilota: www.ansa.it e funziona.
        Oltre il sito pilota, ho inserito una url_regex testata con successo:

        ^.*\b(roma|pisa)\b.*$

        questa regex però mi filtra solo la prima parte della chiamata in uscita che è (non valida al momento) :

        https://www.miosito.roma.it/servizi/well-known/check

        oppure

        https://www.miosito.pisa.it/servizi/well-known/check

        quindi viene “colpita” roma o pisa ed è corretto, ma non riesco invece a far validare una keyword che viene dopo lo “/” ( per esempio servizi oppure .well-known )

        sigh…

        1. Giovanni Sacheli 754 risposte

          Ciao Alessandro!
          Un altro tentativo che puoi fare per filtrare la keyword dopo lo “/” nell’URL, è modificare leggermente l’espressione regolare.
          Puoi provare questa:

          ^./(roma|pisa)/.$

          Questa espressione regolare corrisponderà a URL che contengono “roma” o “pisa” dopo lo “/”. Ad esempio, filtrerà URL come:

          https://www.miosito.roma.it/servizi/well-known/check
          https://www.miosito.pisa.it/servizi/well-known/check

          Spero che questa soluzione funzioni. Fammi sapere se bisogno di ulteriori chiarimenti o aiuto.

          1. Alessandro Cotellessa 3 commenti

            Grazie Giovanni, alla fine ho capito che questi filtri non riescono ad intercettare il traffico cifrato ( https ). Infatti da debug( debug 23,9 ) non viene mai catturato il path in SSL ( ma solo in chiaro HTTP )…. sigh….

            1. Giovanni Sacheli 754 risposte

              Ciao Alessandro,

              Mi dispiace per la frustrazione, capisco il tuo dilemma. Purtroppo, questo è un problema comune quando si cerca di filtrare il traffico HTTPS. La natura crittografata del protocollo HTTPS protegge la privacy degli utenti, ma rende anche più difficile per gli amministratori di sistema vedere e gestire il traffico.

              In teoria, è possibile configurare Squid per decifrare e ispezionare il traffico HTTPS utilizzando una funzione chiamata SSL Bump, ma ciò richiede un certo livello di competenza tecnica e presenta alcune sfide legali ed etiche.

              L’uso di SSL Bump può potenzialmente violare le leggi sulla privacy, a seconda della giurisdizione in cui ti trovi, e può richiedere il consenso degli utenti finali. Inoltre, implementarlo correttamente può richiedere di installare un certificato di autorità di certificazione (CA) personalizzato su ogni dispositivo che si connette attraverso il proxy.

              Se decidi di esplorare questa opzione, ti consiglio di fare una ricerca approfondita e di consultare un professionista della sicurezza informatica o un consulente legale per assicurarti di capire tutte le implicazioni.

              Se non è possibile o desiderabile utilizzare SSL Bump, potresti dover cercare altre soluzioni per gestire il traffico HTTPS. Potrebbe valere la pena esplorare soluzioni alternative o commerciali che possano gestire in modo più efficace il traffico HTTPS.

              Mi dispiace di non poter essere di più aiuto. Buona fortuna!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Ultimi articoli aggiornati

Richiedi un preventivo SEO e Google Ads

Porta il tuo sito web al livello successivo con l’expertise di EVE Milano. La nostra agenzia di Search Marketing ha ricevuto oltre 1123 richieste di preventivo, un segnale chiaro della fiducia che imprenditori e manager, come te, ripongono nella nostra specializzazione tecnica e verticale nella SEO e PPC. Se la tua organizzazione cerca competenze specifiche per emergere nei risultati di Google, noi siamo pronti a fornire quel valore aggiunto. Affidati alla nostra esperienza per fare la differenza.
Richiedi un preventivo

Non perderti altre guide, iscriviti per ricevere un avviso mensile con gli aggiornamenti del blog!

Iscriviti alla newsletter!

Informativa sui cookies

Noi e terze parti selezionate utilizziamo cookie o tecnologie simili per finalità tecniche e, con il tuo consenso, anche per le finalità di esperienza e misurazione come specificato nella cookie policy. Puoi liberamente prestare, rifiutare o revocare il tuo consenso, in qualsiasi momento, accedendo al pannello delle preferenze. Il rifiuto del consenso può rendere non disponibili le relative funzioni. Usa il pulsante “Accetta” per acconsentire. Usa il pulsante “Rifiuta” per continuare senza accettare.