ePrometeusCorsoLinuxLinux
testi articoli
Testi Articoli  Download
Home | Introduzione | Panoramica | Form | Analisi Log | 
CorsoJava è ora Video! Free for all!
Clicca Qui!
Tutorial Perl
Analisi dei log di accesso in Perl
Utilizzo di Analog
Le espressioni regolari
Struttura del programma
Lettura dei parametri
Analisi dei log
Conclusioni


<<< Le espressioni regolari >>>

Le espressioni regolari sono una delle migliori caratteristiche del Perl che lo rendono molto flessibile e anche un po’ particolare. Dato l’uso intensivo che se ne fa in questo programma, sarà opportuno cogliere l’occasione per esaminarle in dettaglio. Le espressioni regolari vengono definite in informatica teorica come delle espressioni che servono a descrivere insiemi di stringhe. L’operazione principale che utilizza una espressione regolare è il matching, cioè la verifica che una stringa appartiene all’insieme descritto dall’espressione regolare.

In realtà il Perl (come pure molti altri programmi) utilizzano questo concetto in maniera più ampia rispetto alla definizione teorica. Innanzitutto il matching non viene applicato soltanto all’intera stringa per la verifica della corrispondenza; normalmente invece viene effettuata una ricerca di sottostringhe che la soddisfino. Naturalmente è possibile specificare che si vuole un matching sull’intera stringa e non su una sottostringa (ed è un caso frequente). Ci sono inoltre altre due varianti di espressione regolare che causano degli effetti collaterali: questi modificano la stringa su cui si effettua il matching. Gli effetti collaterali sono sostituzioni di stringhe e traslazioni, cioè sostituzioni di singoli caratteri e l’utilissima estrazione di sottostringhe.

Per usare le espressioni regolari si usa l’operatore =~, il quale applica ad una stringa il matching e gli effetti collaterali che l’espressione causa. Il primo operando di questo operatore è una variabile scalare, mentre il secondo operando è l’espressione regolare vera e propria, che ha in generale questa forma:

	[<prefisso>]<delim><regexp><delim>[<string><delim> [<suffisso>]]

L’operatore ritorna sempre un valore, che può sempre essere interpretato come vero se l’applicazione dell’espressione regolare ha avuto successo, falso altrimenti. Vediamo ora alcuni esempi:

	(a) /0/
	(b) m/\s*|\w+/
	(c) s/[ \t\n]+/ /g
	(d) tr/a-z/A-Z/

Il <prefisso> può essere m (matching), s (sostituzione), tr (traslazione). Le barre / sono normalmente usate come delimitatori ed hanno una funzione analoga alle virgolette usate per delimitare una stringa. In realtà è possibile utilizzare qualsiasi carattere come delimitatore (è sufficiente che il primo e l’ultimo siano uguali) ma se il delimitatore non è la barra occorre sempre specificare il <prefisso>. Se invece il <delim> è la barra e il <prefisso> è omesso, si assume m. Il <suffisso> serve per specificare delle opzioni sull’effetto collaterale causato dalla espressione regolare, per esempio la ripetizione di una sostituzione, come il (c).

La <regexp> vera e propria utilizza i caratteri alfanumerici nel loro significato letterale (per esempio /a/ matcha "a"), mentre i caratteri non alfanumerici hanno generalmente un significato speciale, e li chiameremo perciò metacaratteri. Nella seguente tabella sono riepilogati i principali metacaratteri e il loro significato.

CARATTERI
.	qualsiasi carattere tranne il newline
[a-z]	qualsiasi carattere elencato 
	(il - genera una sequenza, il ^ inverte la classe)
\s	spazio bianco
\w	una lettera, cifra decimale o _
\d	una cifra decimale
\S	come [^\s]
\W	come [^\w]
\D	come [^\d]
ITERATORI
*	0 o più occorrenze
+	1 o più occorrenze
?	0 o 1 occorrenze
{n}	esattamente n occorrenze
{n,}	almeno n occorrenze
{n,m}	da n a m occorrenze
ALTRO
^	inizio di stringa
$	fine di stringa
|	alternative 
()	raggruppamento

È possibile togliere il significato speciale ad un metacarattere ed usarlo nel suo significato letterale precedendolo con un backslash: per esempio /\*/ matcha "*". Alcuni caratteri alfanumerici invece, se sono preceduti dal backslash diventano metacaratteri e acquistano un significato speciale che normalmente non hanno: per esempio /\d/ matcha una cifra decimale.

Veniamo all’analisi dei metacaratteri: il punto . sostituisce qualsiasi carattere eccetto il newline. Le parentesi quadre racchiudono insiemi di caratteri (le cosiddette classi di caratteri), e matchano una occorrenza tra i caratteri che racchiudono. Per esempio [azt] matcha uno tra i caratteri a, z e t. Le classi possono essere negate ([^azt] matcha qualunque carattere che non sia a, z o t) ed è possibile abbreviare sequenze contigue nel codice ascii di caratteri, utilizzando il trattino: [0-7] abbrevia [01234567].

Una volta definite le espressioni che servono a matchare un carattere, introduciamo gli iteratori che servono a ripetere in vari modi il matching del carattere, metacarattere, o raggruppamento (vedi dopo) che seguono. Per esempio /[0-7]/ matcha una cifra ottale; se utilizziamo l’iteratore +, /[0-7]+/ matcherà "1", "123", "0765". Gli altri iteratori sono ?, che rende opzionale ciò che precede (matcha 0 o 1 occorrenza), l’iteratore * che considera da 0 occorrenze in sù, e gli iteratori {n}, {n,}, {n,m} che matchano n, da n o più, da n a m occorrenze. Naturalmente sarebbe troppo limitante se un iteratore si potesse applicare soltanto ad un carattere: infatti è possibile utilizzare le parentesi tonde per raggruppare una sequenza a cui applicare un iteratore. Per esempio /x([ab]\d)*/ matcha “xa1”, “xa1b2a3” ed anche “x”.

Si può scrivere una espressione regolare composta da più sottoespressioni che matchi una tra varie alternative: questo si ottiene utilizzando l’alternatore |. Infine è possibile matchare dei punti in una stringa che non corrispondono necessariamente ad un carattere: abbiamo ^ che matcha l’inizio di una stringa e $ che matcha la fine. Per esempio /^a|z$/ matcha ogni stringa che comincia per a o finisce per z.

Con il semplice matching (m/<regexp>/) si ricerca una sottostringa corrispondente alla stringa. Con la sostituzione, che ha la sintassi s/<regexp>/<replacement>/ si sostituisce la stringa matchata dall’espressione regolare con un’altra stringa. La prima infatti è effettivamente una espressione regolare, mentre la seconda è una semplice stringa. Infine la traslazione tr/<stringa>/<stringa>/ richiede due stringhe come parametri (anche se è possibile utilizzare la notazione col trattino: 0-7 abbrevia 01234567) e trasla ogni carattere della prima stringa nel corrispondente carattere della seconda).

Adesso dovrebbero essere chiari gli esempi di prima: (a) ricerca il carattere 0 nella sottostringa, (b) ricerca sequenze di spazi bianchi eventualmente vuote o sequenze alfanumeriche non vuote, (c) sostituisce sequenze di spazi, tab e newline con un singolo carattere spazio (la ricerca e sostituzione viene ripetuta per tutta la stringa come specificato dal suffisso g), infine (d) converte in maiuscolo tutti i caratteri minuscoli.

Per finire questa introduzione alle espressioni regolari occorre ricordare che esse sono un potente strumento di analisi lessicale, grazie ai raggruppamenti che analizzano le stringhe e assegnano alle variabili $1, $2, ..., $i. Vediamo un esempio tratto dal programma:

	/^(\d\d?)\/(\w\w\w)\/(\d\d\d\d)$/ 

Questa espressione regolare è soddisfatta da stringhe come “9/Lug/1968” e lascia nella variabile $1 "9", nella $2 "Lug" e nella $3 "1968". La regola è che durante il matching viene assegnata alle variabile $i la sottostringa matchata dalla parte dell’espressione regolare racchiusa nell’i-sima coppia di parentesi.

Un’espressione regolare può essere utilizzata senza l’operatore =~ quando si applica alla variabile di default, $_. In questo caso scrivere semplicemente la <regexp> equivale a scrivere $_ =~ <regexp>. Esiste anche l’operatore !~ che equivale a scrivere !(<exp>=~<regexp>).

ePrometeus s.r.l. - Web Software House & Open Source System Integrator
MILANO - SAN BENEDETTO DEL TRONTO(AP)
Contatti: info@eprometeus.com