Espressioni regolari

Le espressioni regolari, chiamate anche regex o regexp, consistono in modelli che descrivono insiemi di stringhe di caratteri.
Qualcosa di simile come quando si scrive sulla riga di comando di Windows:
		dir *.exe
*.exe‘ sarebbe una “espressione regolare” che descrive tutte le stringhe che iniziano con qualunque carattere seguito da ‘.exe‘, ovvero tutti i file con l’estensione exe.
Il lavoro con le espressioni regolari in Python viene fatto usando il modulo re, che risale al Python 1.5 e fornisce una sintassi per la creazione di modelli simili al Perl. In Python 1.6, il modulo è stato riscritto per dare il supporto alle stringhe unicode e per migliorare le prestazioni.
Il modulo re contiene funzioni per cercare i modelli all’interno di una stringa (search), controllare se una stringa è conforme a un certo criterio descritto da un modello (match), dividere la stringa utilizzando le occorrenze del modello come i punti di rottura (split) o per sostituire tutte le occorrenze del modello con un’altra stringa (sub). Vedremo queste funzioni e un po’ di più avanti nella prossima sezione, ma per ora, vediamo qualcosa in più sulla sintassi delle espressioni regolari.
Patterns
La più semplice espressione regolare consiste in una semplice stringa, che descrive una insieme composto solo dalla stessa stringa. Per esempio, vediamo come la stringa “python” corrisponde all’espressione regolare “python” utilizzando la funzione match:
			import re
			if re.match("python", "python"):
			    print "certo"
Se vogliamo verificare se la stringa è “python”, “Jython”, “Cython” o qualsiasi altra cosa che termina in “ython” può utilizzare il carattere jolly, il punto ‘.‘:
			re.match(".ython", "python")
			re.match(".ython", "jython")
L’espressione regolare “.ython” descriverebbe tutte le stringhe costituite da qualsiasi carattere tranne il carattere di nuova linea, seguito da “ython”. Qualsiasi carattere e solo uno. Non zero, nè due, nè tre.
Nel caso in cui abbiamo bisogno del carattere ‘.‘ nelle espressioni regolari, o qualunque altro carattere speciale, che vedremo di seguito, lo dovremmo scappare usando un backslash.
Per controllare se la stringa è di 3 caratteri seguita da un periodo o un punto, per esempio, possiamo utilizzare quanto segue:
			re.match("...\.", "abc.")
Se abbiamo bisogno di un’espressione che si dimostra vero solo per le stringhe “python”, “jython” e “cython” e nessun’altra, potremmo usare il carattere ‘|’ per esprimere tre alternative scrivendo i sottopattern completi:
			re.match("python|jython|cython", "python")
… o solo la parte che può cambiare, fra parentesi tonde, formando ciò che è noto come un gruppo. I gruppi sono molto importanti quando si lavora con espressioni regolari e questo non è l’unico uso, come vedremo nella sezione successiva.
			re.match("(p|j|c)ython", "python")
Un’altra opzione sarebbe quella di racchiudere i caratteri ‘p’, ‘j’ e ‘c’ tra parentesi quadre per formare una classe di caratteri, indicando che questa posizione possono essere collocato qualsiasi dei caratteri della classe.
			re.match("[pjc]ython", "python")
E se volessimo controllare se la stringa è “python0”, “python1”, “python2”, … , “python9”? Invece di dover racchiudere le 10 cifre tra parentesi si può utilizzare il trattino, usato per indicare gli intervalli. Per esempio [a-d] indicherebbe tutte le lettere minuscole da ‘a‘ a ‘d‘, [0-9] sarebbero tutti i numeri da ‘0‘ a ‘9‘.
			re.match("python[0-9]", "python0")
Se volessimo, per esempio, che l’ultimo carattere fosse una cifra o la lettera, semplicemente scriveremo tra parentesi quadre tutti i criteri, uno dopo l’altro.
			re.match("python[0-9a-zA-Z]", "pythonp")
È necessario notificare che all’interno delle classi di caratteri i caratteri speciali non hanno bisogno di avere il backskash o il carattere di escape. Per verificare se la stringa è “python.” o “python,”, scriveremo:
			re.match("python[.,]", "python.")
… e non
			re.match("python[\.,]", "python.")
… poiché in questo caso si verificherebbe se la stringa è “python.”, “python,” o “python\”.
Gli insiemi di caratteri possono anche essere negati con l’uso del simbolo ‘^‘. L’espressione “python[^0-9a-z]”, per esempio, indica che siamo interessati a stringhe che iniziano con “python” e come ultimo carattere, avere qualcosa che non è né una lettera minuscola o un numero.
			re.match("python[^0-9a-z]", "python+")
L’uso di [0-9] per fare riferimento ad un digito non è molto comune, visto che, quando si verifica che un carattere è una cifra c’è una sequenza speciale equivalente: ‘\d‘. Ci sono altre sequenze disponibili che sono elencati qui sotto:
Sequenze disponibili
  • “\d”: un dígito. Equivalente a [0-9]
  • “\D”: qualsiasi carattere diverso da un dígito. Equivalente a [^0-9]
  • “\w”: qualsiasi caratter alfanumerico. Equivalente a a-zA-Z0-9_][
  • “\W”: qualsiasi caratter non alfanumerico. Equivalente a [^a-zA-Z0-9_]
  • “\s”: qualsiasi caratter in bianco. Equivalente a [ \t\n\r\f\v]
  • “\S”: qualsiasi caratter che non sia in bianco. Equivalente a [^ \t\n\r\f\v]
Vediamo ora come rappresentare ripetizioni di caratteri, dal momento che sarebbe inutile scrivere, ad esempio, una espressione regolare di 30 caratteri ‘\d‘ per cercare numeri da 30 cifre. Per questo abbiamo bisogno dei caratteri speciali +, * e ?. Oltre alle parentesi graffe {}.
Il carattere + indica che ciò che abbiamo a sinistra è un carattere come ‘a‘, una classe ‘[abc]‘ o un sotto-modello come ‘(abc)‘ che possono trovarsi una o più volte. Ad esempio l’espressione regolare “python +” descriverebbe le stringhe “python“, “pythonn” e “pythonnn“, ma non “pytho“, perché ci deve essere almeno una n.
Il carattere * è simile a +, ma in questo caso ciò che si trova sulla sinistra può avere zero o più occorrenze.
Il carattere ? indica opzionalità, cioè, ciò che si trova asinistra può o non può apparire (può apparire 0 o 1 volta).
Infine, le parentesi sono utilizzate per indicare il numero esatto di volte in cui il carattere può apparire a sinistra, o anche l’intervallo di volte che può apparire. Per esempio {3} indica che deve apparire esattamente 3 volte; {3,8} indicherebbe che deve apparire da 3 a 8 volte; {8} da 0 a 8 volte; e {3,} volte tre o più (quante ne sono).
Un altro elemento interessante nelle espressioni regolari, infine, è la specificazione delle posizioni in cui si deve trovare la stringa, facilitato dall’uso di ^ e $, che indicano, rispettivamente, l’elemento sul quale dovrebbe agire: o andare all’inizio della stringa o alla fine di questa.
La stringa “http://mundogeek.net “, per esempio, seguirebbe l’espressione regolare “^http“, mentre la stringa “Il protocollo è http” non lo seguirebbe , perché la particella “http” della stringa non si trova all’inizio della stringa.
Utilizzando il modulo re
Abbiamo visto superficialmente come si utilizza la funzione match del modulo re per verificare se una stringa si inserisce in un dato pattern. Il primo parametro della funzione è l’espressione regolare; il secondo, la stringa da controllare e vi è un terzo parametro facoltativo che contiene vari flag che possono essere utilizzate per modificare il comportamento delle espressioni regolari.
Alcuni esempi di flags del modulo re sono re.IGNORECASE che non prende in considerazione se le lettere sono maiuscole o minuscole o re.VERBOSE, che induce a ignorare gli spazi e i commenti nella stringa che rappresenta l’espressione regolare.
Il valore di ritorno della funzione restituisce None se la stringa non si adatta al modello o ad un oggetto di tipo MatchObject in caso contrario. Questo oggetto, MatchObject, dispone di metodi start ed end che restituiscono la posizione in cui la sottostringa inizia e finisce e metodi group e groups che forniscono l’accesso a gruppi che hanno portato al riconoscimento della catena.
Chiamando il metodo group senza parentesi restituisce il gruppo 0 della stringa riconosciuta. Il gruppo 0 è la sottostringa riconosciuta dall’intera espressione regolare, anche se non ci sono parentesi che delimitano il gruppo.
			>>> mo = re.match("http://.+\net", "http://mundogeek.net")
			>>> print mo.group()
			http://mundogeek.net
			>>> 
Potremmo creare gruppi utilizzando le parentesi, come abbiamo imparato nella sezione precedente, ottenendo la catena che ci interessa.
			>>> mo = re.match("http://(.+)\net", "http://mundogeek.net")
			>>> print mo.group(0)
			http://mundogeek.net
			>>> print mo.group(1)
			mundogeek
			>>> 
Il metodo groups, invece, restituisce un elenco con tutti i gruppi ad eccezione del gruppo 0, che viene omesso.
			>>> mo = re.match("http://(.+)\(.{3})", "http://mundogeek.net")
			>>> print mo.groups()
			(‘mundogeek’, ‘net’)
La funzione di ricerca (search) del modulo re funziona in modo simile a match, con gli stessi parametri e restituiscono lo stesso valore. L’unica differenza è che utilizzando match, la stringa deve corrispondere al modello dal primo carattere della stringa, mentre con search qualsiasi parte della stringa può corrispondere al modello. Per questo motivo il metodo start di un oggetto MatchObject ottenuto con funzione match restituirà sempre 0, mentre con search potrebbe non essere così.
Un’altra funzione di ricerca del modulo re è findall. Questo prende gli stessi parametri delle due funzioni precedenti, ma restituisce una lista con le sotto-stringhe che soddisfano il modello.
In alternativa, se non vogliamo che tutte le corrispondenze, è quello di utilizzare finditer, che restituisce un iteratore da consultare uno a uno le diverse MatchObject.
Le espressioni regolari consentono di realizzare non solo ricerche o verifiche, ma, come discusso in precedenza, di avere funzioni per suddividere la stringa o realizzare le sostituzioni.
La funzione split senza andare oltre prende come parametri di un modello, una stringa e un intero opzionale che indica il numero massimo di elementi che si desidera dividere la stringa, e utilizza il modello con due punti per la stringa, restituendo una lista con le sottostringhe.
La funzione sub prende come parametri un modello per sostituire una stringa da utilizzare come rimpiazzo ogni volta che troviamo il modello, sulla stringa su cui effettuare le sostituzioni e un intero opzionale che indica il numero massimo di sostituzioni che vogliano realizzare.
Quando si chiamano questi metodi, ciò che accade è che si crea un nuovo oggetto di tipo RegexObject che rappresenta l’espressione regolare, e si chiama a metodi di questo oggetto che hanno gli stessi nomi delle funzioni del modulo.
Se usiamo lo stesso modello più volte potremmo voler creare un oggetto di questo tipo e chiamarne i suoi metodi noi stessi; in questo modo si evita che l’interprete debba creare un nuovo oggetto ogni volta che utilizziamo il modello e così miglioriamo le prestazioni dell’applicazione.
Per creare un oggetto RegexObject si utilizza la funzione compile del modulo, al quale viene passato come parametro una stringa che rappresenta il modello che vogliamo usare per la nostra espressione regolare e, facoltativamente, una serie di flags come quelli discussi in precedenza.

Similari
Overloading di metodi in Java
12% Java
Un metodo overload viene utilizzato per riutilizzare il nome di un metodo ma con argomenti diversi, opzionalmente con un differente tipo di ritorno. [expand title=”Regole per overload” startwrap=”” endwrap=”” excerpt=”⤽” s…
Modi di fare e di non fare in Python
11% Python
Questo documento può essere considerato un compagno del tutorial di Python. Viene illustrato come utilizzare Python, e quasi ancora più importante, come non usare Python. [expand title=”Costrutti del linguaggio che non dov…
redirect 301 usando mod_alias
9% Server
mod_alias è fondamentalmente la versione più semplice di mod_rewrite. Non può fare le cose che fa mod_rewrite, ad esempio modificare la stringa di query. Per eseguire reindirizzamenti nel server web Apache è possibile di u…
Installare Python e Django su Windows
8% Django
Quando ci riferiamo allo sviluppo web con Python, la prima cosa che viene in mente è usare un qualche framework. Il più famoso e utilizzato da tutti è il Django, ma non è l’unico. Ci sono Pylons, Grok, TurboGears e Zope: t…
Metodi magici e costanti predefinite in PHP
8% Php
PHP fornisce un insieme di costanti predefinite e metodi magici per i nostri programmi. A differenza delle normali costanti i quali si impostano con define(), il valore delle costanti predefinite o speciali dipendono da do…