JavaScript/Espressioni regolari
JavaScript, oltre ai metodi già spiegati relativi all'oggetto String, offre potenti funzioni di manipolazione stringa con le espressioni regolari.
Le espressioni regolari sono un particolare linguaggio con il quale è possibile abbinare le stringhe per effettuare ricerche, sostituzioni o semplici confronti.
Ad esempio, se nei precedenti capitoli abbiamo visto come sostituire tutte le "a" in una stringa (con il metodo replace
) dopo aver letto questo capitolo potremo sostituire tutte le parole con dei numeri, o anche semplicemente tutte le cifre con un carattere nullo.
Per approfondire, vedi Espressioni regolari. |
Per approfondire su Wikipedia, vedi la voce Espressioni regolari. |
Le espressioni regolari di JavaScript sono molto simili a quelle del Perl. In questo capitolo tuttavia ci soffermeremo a spiegarne almeno i fondamenti.
Espressioni regolari in JavaScript
[modifica | modifica sorgente]L'uso delle espressioni regolari in JavaScript si basa sul'oggetto RegExp
:
var myRegex = new RegExp ("testo della regex", "parametri");
var r = new RegExp ("Ciao *", "g");
Il primo parametro è l'espressione regolare vera e propria, mentre il secondo (opzionale) è una stringa combinando uno o più parametri espressi come lettere:
- g indica un abbinamento globale (ovvero verranno abbinate tutte le istanze che corrispondono all'espressione regolare e non solo la prima)
- i indica di non distinguere tra maiuscole e minuscole
Esiste anche una forma abbreviata per la creazione, che useremo più spesso:
var myRegex = /testo della regex/parametri;
var r = /[Ee]spressione regolare/ig;
Sintassi delle espressioni regolari
[modifica | modifica sorgente]L'espressione regolare più semplice che possiamo dichiarare è quella che non contiene caratteri speciali, ma il suo uso sarà abbastanza limitato. Ad esempio l'espressione regolare /JavaScript/
abbinerà solo le stringhe "JavaScript". Per rendere le espressioni regolari invece veramente potenti, usiamo i cosiddetti caratteri speciali, che non identificano il carattere stesso, ma altri caratteri particolari o gruppi di caratteri.
Testo e punteggiatura
[modifica | modifica sorgente]Carattere | Abbina | Esempio |
---|---|---|
\d |
Una cifra da 0 a 9 | \d\d\d abbina 423 ma non 04
|
\D |
Qualsiasi carattere escluso le cifre | \D abbina % o r , ma non 3
|
\w |
Ogni carattere di parola (A-Z, a-z, 0-9, underscore) | \w\w abbina A2 o 3_ , ma non d$ o ()
|
\W |
Ogni carattere non di parola | \W non abbina 5 , _ , a
|
\s |
Ogni carattere di spazio (spazio, tab, nuova riga, ecc...) | \s abbina tab o \n ma non .
|
\S |
Ogni carattere non di spazio | \S\s abbina "% ", ma non %_
|
. |
Ogni carattere singolo | . abbina b e °
|
[...] |
Qualsiasi carattere indicato tra le parentesi | [ciao] abbina c e o , ma non b ; [0-9] equivale a \d , perché abbina ogni carattere tra 0 e 9 (ad esempio 5 ma non k )
|
[^...] |
Qualsiasi carattere esclusi quelli indicati tra le parentesi | [^ciao] abbina b e q , ma non c ; [^a-z] abbina ogni carattere che non è compreso tra la a e la z (ad esempio @ ma non k )
|
Un primo esempio
[modifica | modifica sorgente]Vediamo un primo esempio per iniziare a capire come utilizzare in concreto le nostre espressioni regolari.
Supponiamo di voler creare un modulo per la registrazione ad un sito e chiediamo all'utente di inserire come username una parola che non contenga caratteri speciali, ma solo lettere, numeri e il simbolo di underscore.
Potrebbe venire in mente che per fare questo ci possa tornare utile il metacarattere visto in precedenza \w
. Tuttavia questo non è possibile, in quanto \w
abbina un singolo carattere non di parola: potremmo ad esempio controllare che il nostro nome utente si abbini con \w\w\w\w
, ma questo funzionerebbe solo con un username di quattro lettere. La cosa più comoda è quindi verificare che nella nostra stringa ci sia un carattere non di parola e, in caso ciò sia vero, chiedere all'utente di scegliere un diverso username.
Per verificare che una regex abbini una stringa, usiamo il metodo test
dell'oggetto RegExp che restituisce true
se la regex si abbina, false
in caso contrario:
var username = document.form.username.value; //prende il nome dal form
var myRegex = /\W/i; //non serve effettuare una ricerca globale
//in quanto se c'è anche un solo carattere non di parola l'username non è valido
var non_valido = myRegex.test(username);
if (non_valido == true) {
alert('Nome utente non valido. Riprova');
} else {
//prosegui...
}
Caratteri di ripetizione
[modifica | modifica sorgente]I seguenti caratteri servono per abbinare gli elementi definiti precedentemente più volte in base a quanto indicato.
Carattere | Abbina | Esempio |
---|---|---|
{n} |
Abbina l'elemento precedente n volte | \d{3} abbina 223 ma non 04
|
{n,} |
Abbina l'elemento precedente n o più volte | \w{2,} abbina ac , a4cr , a_4 ma non 4 o d4gsz%
|
{n, m} |
Abbina l'elemento precedente da un minimo di n volte a un massimo di m volte | \d{3,5} abbina 223 , 3566 ma non 04 o 692159
|
? |
Abbina l'elemento precedente zero o una volta | ciao? abbina cia oppure ciao (il punto interrogativo si riferisce solo all'ultimo carattere)
|
+ |
Abbina l'elemento precedente una o più volte | ciao+ abbina ciao oppure ciaoooooo
|
* |
Abbina l'elemento precedente zero o più volte | .* abbina qualsiasi stringa (sia che sia vuota sia che contenga caratteri speciali); a* abbina una stringa vuota ma anche a , aa , ecc...
|
Supponiamo ad esempio di aver chiesto all'utente di inserire un CAP e di voler verificare che sia valido:
var cap = document.form.username.value; //prende il nome dal form
var myRegex = /\d{5}/; //5 cifre
if (myRegex.test(cap)) {
//il cap è valido...
} else {
alert('Inserire un CAP valido');
}
Posizione
[modifica | modifica sorgente]Analizziamo ora alcuni caratteri di posizione, che non specificano un particolare tipo di caratteri, bensì una particolare posizione nella stringa.
Carattere | Abbina | Esempio |
---|---|---|
^ |
Abbina l'inizio della stringa o, nel caso di stringhe su righe multiple, l'inizio di una riga.[1] | ^\d abbina 2 , ma solo se ad inizio riga
|
$ |
Abbina la fine della stringa o, nel caso di stringhe su righe multiple, la fine di una riga.[1] | \w$ abbina a , ma solo se a fine riga
|
\b |
Abbina un limite di parola, cioè il punto tra la fine di una parola e il primo carattere di parola | a\b abbina a , ma solo se si trova alla fine di una parola. Questo può servire se si vuole abbinare solo una parola: \bparola\b .
|
\B |
Abbina una posizione che non è un limite di parola | \Ba\B abbina a , ma solo se si trova in mezzo ad una parola, non agli estremi
|
Raggruppare i caratteri
[modifica | modifica sorgente]Per raggruppare i caratteri nelle espressioni regolari si usano le parentesi tonde: ()
. Ad esempio, (\d\w)+
abbina una o più sequenze di una cifra e un carattere di parola (ad esempio 5a7v4g
ma non 3f5r8
. All'interno delle parentesi è anche possibile usare il carattere |
per indicare una scelta tra due alternative: (Java|VB)Script
abbina sia JavaScript che VBScript.
Backreference
[modifica | modifica sorgente]I backreference sono una interessante funzionalità delle espressioni regolari che permette di riferirsi ai caratteri abbinati da un gruppo indicato in precedenza con le parentesi. Per indicare una backreference si usa la sintassi \n
, dove n è il numero del gruppo a cui si vuole riferire: il primo gruppo sarà indicato con \1
, il secondo con \2
, ecc...
Supponiamo ad esempio di volere una stringa formata da un solo carattere di parola ripetuto più volte, qualunque esso sia (ad esempio aaaaaaaa
ma non aaabaaa
: il primo carattere sarà quindi \w
. Per poter fare riferimento al carattere abbinato da \w
lo mettiamo tra parentesi: (\w)
; ora \1
abbinerà il carattere abbinato all'inizio. La nostra regex sarà quindi (\w)\1+
.
Metodi
[modifica | modifica sorgente]Le principali funzioni utilizzate insieme alle espressioni regolari sono le funzioni split()
, replace()
, search()
e match()
dell'oggetto String. La maggior parte di esse sono state spiegate nel modulo relativo, ma l'uso delle regexp le arricchisce di molto.
split()
[modifica | modifica sorgente]Il metodo split()
divide la stringa in base a quanto indicato nel parametro e restituisce un array che contiene tutte le sottostringhe in cui è stato diviso. Supponiamo ad esempio di voler ottenere in un array le parole contenute in un testo, ad esempio per contarne il numero: dovremo quindi trovare un'espressione regolare che abbini ciascun i caratteri tra una parola e l'altra.
Per fare questo possiamo avvalerci del metacarattere \W
che abbina ogni carattere non di parola. Dovremo tuttavia prevedere che ci siano più caratteri non stringa tra le parole (ad esempio ,
). Usiamo quindi \W+
: var parole = testo.split(/\W+/g);
.
replace()
[modifica | modifica sorgente]Il metodo replace ()
sostituisce il testo abbinato dalla regex indicata come primo parametro con il testo indicato nella seconda.
Si ricordi sempre che per sostituire tutte le occorrenze abbinate dalla regex è necessario impostare il parametro globale della regex; supponiamo di voler eliminare tutti i caratteri da una stringa in modo da ottenere un numero intero:
var str = new String('245dfh57w');
var num = str.replace(/\D/, ''); //restituisce "245fh57w"
var num2 = str.replace(/\D/g, ''); //restituisce "24557"
Anche nei replace è possibile utilizzare dei backreference, usando la sintassi $n
:
//corregge le diciture "cm n" con "n cm"
var str = "La base misura cm 30 e l'altezza cm 50";
var str2 = str.replace(/([mdc]m) (\d+([\.,]\d+)?)/gi, "$2 $1");
Esaminiamo la nostra regex /([mdc]m) ((\d+(\.\d+)?)/gi
:
[mdc]m
serve per abbinare uno tra i tre caratteri m, d o c seguiti da m: in questo modo verranno abbinati cm, dm e mm;- le parentesi attorno (
([mdc]m)
) servono per poter usare il backreference; \d+
abbina una o più cifre disposte di seguito, che costituiscono la parte intera della nostra misura- il carattere di punto con davanti la barra non sta a significare il metacarattere punto bensì il punto vero e proprio (
.
), che delimita i decimali.[\.,]
serve per abbinare o un punto o una virgola; [\.,]\d+
abbina così la parte decimale della misura (es..474
); questa tuttavia, essendo opzionale (nel caso di numeri interi) è posta tra parentesi e seguita da?
che indica che la parte decimale può essere presente una volta o non esistere affatto;(\d+([\.,]\d+)?)
è infine tutto tra parentesi per permettere l'utilizzo del backreference;gi
indicano di effettuare un abbinamento globale non sensibile alle maiuscole.
È possibile abbinare anche delle posizioni:
var str = "Lorem ipsum dolor sit amet";
var str2 = str.replace(/\B/g, '|'); //sostituisce i caratteri non di fine stringa con "|"
//ora str2 contiene L|o|r|e|m i|p|s|u|m d|o|l|o|r s|i|t a|m|e|t
search()
[modifica | modifica sorgente]Il metodo search()
è una versione avanzata del già visto metodo indexOf()
, in quanto supporta le espressioni regolari, restituendo la posizione nella quale viene abbinata la regex indicata come parametro (-1 indica che non è stato trovato alcun abbinamento).
match()
[modifica | modifica sorgente]Il metodo match()
abbina la regex nel testo cercato e restituisce un array delle stringhe abbinate. Questo è molto utile in quanto permette di sapere realmente i caratteri abbinati dalla regex.
Ad esempio supponiamo di voler cercare tutti gli indirizzi e-mail presenti in un testo:
var myRegex = /\b\w+@\w+\.\w{2,3}\b/gi;
var indirizzi = testo.match(myRegex);
La nostra regex abbina una parola intera (\b...\b
) composta da uno o più caratteri parola (\w+
) seguiti da una chiocciola, altri caratteri di parola, seguiti da un punto (\.
: il backslash serve per evitare di usare il metacarattere punto) e da due o tre caratteri di parola (\w{2,3}
).