JavaScript

pagine di Roberto Ricci L.S. "A. Righi", Bologna.

Espressioni regolari

Dovendo effettuare la ricerca di un file di cui non si conosca con esattezza il nome, capita di usare i caratteri ? e *. Ad esempio:
'data?.dat' permette di selezionare
data1.dat
data2.dat
datax.dat
dataN.dat
'data*.dat' permette di selezionare
data.dat
data1.dat
data2.dat
data12.dat
datax.dat
dataXYZ.dat
L'uso dei caratteri ? e *, sebbene limitato, consente di farsi una prima idea di come funzionano le espressioni regolari.

Nel 1956 Stephen Kleene, un matematico, a partire da un lavoro di McCulloch e Pitts sulle reti neuronali, introdusse il concetto di espressione regolare per descrivere quella che chiamò "algebra degli insiemi regolari". Ripreso in seguito da informatici, il concetto ebbe una prima applicazione pratica nell'editor Unix chiamato qed.

Con espressioni regolari è possibile:

Una espressione regolare è dunque una metaespressione, ovvero uno schema di espressione, un testo formato da normali caratteri e metacaratteri.

In JavaScript ha forma del tipo

/schema/ind

oppure è un oggetto

new RegExp("schema"[, "ind"])

dove schema è il testo dell'espressione regolare e ind è un indicatore ottenuto da una combinazione delle lettere:

Ad esempio:
/ab+c/i
new RegExp("ab+c", "i")
re = /\w+/
re = new RegExp("\\w+")

dove + e \w sono caratteri speciali, metacaratteri, come gli altri della seguente tabella

Carattere Descrizione Esempi
\

Davanti a caratteri normali permette di interpretarli come metacaratteri

oppure

Davanti a metacaratteri indica di interpetarli alla lettera, come caratteri normali.

/b/ sta per il carattere 'b' mentre /\b/ è un metacarattere per indicare inizio/fine di una parola.

/a*/ indica una 'a' ripetuta 0 o più volte mentre /a\*/ individua 'a*'.

^ Individua il carattere iniziale. Se l'indicatore i è attivo, individua ogni carattere che segue immediatamente il carattere di a capo. /^A/ non individua 'A' in "una A" ma la prima 'A' in "Ancora A"
$ Individua il carattere finale. Se l'indicatore i è attivo, individua ogni carattere che termina la riga. /t$/ non individua la 't' in "vetro" bensì in "pet"
* Considera 0 o più volte il precedente elemento dello schema. /bo*/ individua 'boooo' in "rispose con un booooh" e 'b' in "Un brivido" ma nulla in "orologio".
+ Considera 0 o più volte il precedente elemento dello schema. Equivale a {1,} /a+/ individua 'a' in "bianco" e 'aaaaaaa' in "biaaaaaaanchissimo".
? Considera 0 o 1 volta il precedente elemento dello schema.

Se usato immediatamente dopo un quantificatore +, ?, o {}, forza a individuare il minimo numero di volte, al contrario individua il massimo nmero di volte.

Usato anche per anticipazioni come indicato per i metacaratteri (?=),(?!), e (?:)

/e?lo?/ individua 'el' in "angelo" e 'le' in "angolo."
. Individua qualunque carattere eccetto quello di a capo. /.n/ individua 'on' e 'in' in "nel mondo dipinto di blu", ma non 'nel'.
(x) Individua 'x' e ricorda l'occorrenza negli elementi [1], ..., [n] in un array oppure nelle proprietà predefinite $1, ...,$9 dell'oggetto RegExp /(foo)/ individua e ricorda 'for' in "informazione"
(?:x) Individua 'x' ma senza memorizzare
x(?=y) Individua 'x' solo se 'x' è seguita da 'y'. /Mario(?=Rossi)/ Individua 'Mario' solo s seguito da'Rossi'.
/ Mario(?=Rossi|Bianchi)/ individua 'Mario'solo se seguito da 'Rossi' o da 'Bianchi'. Però né 'Rossi' né 'Bianchi' vengono individuati
x(?!y) Individua 'x' solo se 'x' non è seguito da 'y'. /\d+(?!\.)/ individua un numero solo se non seguito da un punto.
/\d+(?!\.)/.exec("3.141") individua 141 ma non 3.141.
x|y Individua 'x' oppure 'y'. /verde|rossa/ individua 'verde' in "mela verde e rossa" e 'rossa' in "mela rossa"
{n} Dove n è un intero non negativo, consente di individuare esattamente n occorrenze dello schema he precede. /a{2}/ non individua 'a' in "bianco" ma tutte le 'a' di "biaanco" e le prime due in "biaaaanco"
{n,} Dove n è un intero non negativo, consente di individuare almeno n occorrenze dello schema he precede. /a{2,}/ non individua 'a' in "bianco" ma tutte le 'a' di "biaanco" e anche di "biaaaanco"
{n,m} Dove n d m sono interi non negativi,n<m, consente di individuare almeno n e al più m occorrenze dello schema he precede. /a{2,3}/ non individua 'a' in "bianco" ma tutte le 'a' di "biaanco" e anche 'aaa' di "biaaaaaanco".
[xyz] Forma un insieme di caratteri. Individua uno qualunque di tali caratteri. Si può rappresentare anche un intervallo servendosi del trattino. /[abcd]/, che si può scrivere anche [a-c], individua 'b' in "bello" and the 'c' in "losco"
[^xyz] Rappresenta il complementare dell'insieme di caratteri elencato. Individua uno qualunque dei caratteri non elencato. /[^abc]/ , ovvero [^a-c], individua per primo'r' in "braccio" and 'h' in "chioma"
[\b] Individua il carattere spazio, da non confondere con \b.
\b Individua i limiti di una parola, come spazi o a capo, da non confondere con [\b]. /\bn\w/ individua 'no' in "noosfera";
/\wa\b/ individua 'ta' in "travolta dal caso"
\B Evita i limiti di una parola. /\B\wa/ individua 'ta' in "lattante";
/\w\Ba/ individua 'ca' in "turista per caso"
\cX Dove X è una lettera nell'intervallo A - Z. Individua caratteri di controllo. /\cM/ individua [ctrl]-M.
\d Individua una cifra, equivalentemente a [0-9]. /\d/ o /[0-9]/ individua '2' in "BA231CX è la targa"
\D Individua un carattere che non sia una cifra, equivalentemente a [^0-9]. /\D/ o /[^0-9]/ individua 'B' in "BA231CX è la targa"
\f \n \r \t \v Individuano un form-feed, un linefeed, un carriage return, un tab, un vertical tab rispettivamente.
\s Individua un carattere spazio singolo, tab, form feed, line feed. Equivale a [\f\n\r\t\u00A0\u2028\u2029] /\s\w*/ individua ' bar' in "caffè bar."
\S Individua qualunque carattere diverso da uno spazio. Equivale a [^ \f\n\r\t\u00A0\u2028\u2029] /\S/\w* individua 'caffè' in "caffè bar."
\w Individua un qualunque carattere alfanumerico incluso l'underscore. Equivale a [A-Za-z0-9_] /\w/ individua 'a' in "alfanumerico", '5' in "$5.28," e '3' in "3D."
\W Equivale a [^A-Za-z0-9_] /\W/ o [^$A-Za-z0-9_]/ individua '%' in "50%."
\n Dove n è un intero non negativo. Lo zero individua il carattere NUL altrimenti a back reference to the last substring matching the n parenthetical in the regular expression (counting left parentheses). /apple(,)\sorange\1/ individua 'apple, orange', in "apple, orange, cherry, peach."
\xhh \uhhhh Individuano il carattere con codice esadecimale hh o hhhh rispettivamente.

L'ordine di precedenza dei vari tipi di operatori per espressioni regolari, dall'alto al basso, è riportato nella tabella seguente:

Operatori Descrizione
\ Escape
(), (?:), (?=), [] Parentesi
*, +, ?, {n}, {n,}, {n,m} Quantificatori
^, $, \qualunque metacarattere Ancore e Sequenze
| Alternativa

I caratteri normali hanno precedenza rispetto all'operatore di alternativa per cui /m|food/ individua 'm' o 'food'mentre per individuare 'mood' o 'food' occorre usare /(m|f)ood/.

Le espressioni regolari sono utilizzate attraverso metodi degli oggetti RegExp e String:

Oggetto Metodo Descrizione Esempio
RegExp exec(stringa) cerca lo schema nella stringa e restituisce un array
reg=new RegExp("","")
reg.exec() =
RegExp test(stringa) verifica la presenza dello schema nella stringa
reg=new RegExp("","")
reg.test() =
String match(schema) esegue una ricerca di uno schema in una stringa. Restituisce un array di informazione oppure null.
reg=new RegExp("","")
.match(reg)=
String replace(schema, nuova stringa) nuova stringa può essere anche $$ (per '$'), $& (per la sottostringa individuata), $` (per la porzione di stringa che precede la stringa individuata), $´(per la porzione seguente),$n o $nn (per la sottostringa individuata nella n-esima parentesi).
reg=new RegExp("","")
str=)
str.replace(reg,")=
String replace(schema, function) La chiamata alla function avviene dopo che è stato eseguito il confronto con lo schema (questo uso di una function è detto espressione lambda). La function, che restituisce la nuova stringa, ha i parametri
  1. holds the complete matched substring
  2. remembered submatch strings
  3. ...
  4. remembered submatch strings
  5. the offset within the string where the match occurred
"XXzzzz".replace
  (/(X*)(z*)/,
   function (
	str, 
	p1, 
	p2, 
	offset, 
	s) {
     return str + " - " + p1 + " , " + p2;
   }
  ) 
restituisce XX.zzzz - XX , zzzz.
String search(schema) Restituisce la posizione della sottostringa individuata, altrimenti -1.
reg=new RegExp("","")
.searc(reg)=
String split(schema) usa una espressione regolare o una stringa per suddividere una stringa in un array di sottostringhe
reg=new RegExp("","")
.split(reg)=

Esempi:

  1. esempio introduttivo
  2. scompone URI
  3. elimina parole doppie
  4. riconosce numeri naturali
  5. trasforma misure Fahrenheit in Celsius
  6. valida indirizzo e-mail

Esercizi: