Articoli Manifesto Tools Links Canali Libri Contatti ?
Linguaggi / Regular Expressions

Regular Expressions

Abstract
Per molti restano arcane e contorte sequenze di simboli, ma una volta imparate ad usarle diventa quasi impossibile pensare di risolvere alcuni problemi, in maniera compatta e veloce, senza di esse.
Data di stesura: 22/09/2002
Data di pubblicazione: 22/09/2002
Ultima modifica: 04/04/2006
di Marco Lamberto Discuti sul forum   Stampa

[A-Z_\d]+\s*=(?:@[A-Z_\d]+\s*\(\
(?:.*?[^\\][@"]\s*)?\)@|[^@]+)*
Per gli "amici" sono le "regex", per il resto del mondo sono "quella sequenza astrusa di caratteri assolutamente senza senso".

A cosa servono?

La risposta è semplice: pattern matching.
Ovvero la ricerca (matching) di sottostringhe (patterns) all'interno di un testo o, con alcune precauzioni, anche all'interno di una porzione di dati binari.
C'è da notare che solitamente le regex permettono sia la ricerca che la successiva sostituzione del pattern con una sequenza di caratteri data.

Cosa sono?

Le regular expression sono un formalismo, solitamente sono una sequenza di caratteri atte a descrivere un insieme di stringhe.
carattere A meno di caratteri speciali riservati per le regex, che è necessario far precedere da uno '\', costituisce un pattern da rintracciare così com'è.
^ Identifica l'inzio della riga
$ Identifica la fine della riga
[...] Tra parentesi quadre viene identificato un insieme di caratteri, il match è positivo quando almeno uno fra questi viene trovato. Se viene usato un '-' fra due caratteri questo viene interpretato com un intervallo che comprende tutti i valori ASCII fra loro, estremi inclusi.
. Un carattere qualsiasi.
? Match di zero o una volta del pattern che precede il carattere '?'.
* Match di zero o più volte del pattern che precede il carattere '*'.
+ Match di una o più volte del pattern che precede il carattere '+'.
| Match del pattern che lo precede o di quello che segue.
(...) Le parentesi tonde raggruppano uno o più patterns e rispettivi modificatori.
Semplice match di una data: [0-9]+/[0-9A-Za-z]+/[0-9]+
Una linea intera: ^.*$
Un file con nome ed estensione: ^(.+)\.(.+)$
Con un applet di esempio, proveniente dal sito del progetto gnu.regexp per Java, potete fare alcune prove liberamente senza dover scrivere nulla al di fuori della regex.

Perché e quando conviene usarle?

Il perché dell'utilità e evidente, una regex è una descrizione compatta di un insieme: è in grado di catturare una serie di varianti che normalmente richiederebbero la scrittura di decine di righe di codice ad hoc. Senza dimenticare che modificare, correggere, estendere un codice per un pattern matching ad hoc tende ad essere un problema più complicato di una regex, per quanto complessa essa sia.
Spesso con una regex mediamente complessa si riesce ad evitare di dover scrivere diverse centinaia di righe di codice (intricato per via di numerosi blocchi condizionali).
  1. #!/usr/bin/perl -w 
  2.  
  3. foreach $var (@ARGV) { 
  4.   printf("'%s' %d\n", 
  5.     $var, 
  6.     $var =~ /[1-5] settembre 20[0-9][0-9]/); 
Questa semplice regex, evidenziata sopra in grassetto, ricerca all'interno della variabile $var tutte le sequenze di caratteri che comincino coi numeri da 1 a 5, seguiti da " settembre 20" e terminate con due cifre fra 0 e 9.
La stessa cosa in C potrebbe essere scritta senza l'uso della libregex così:
  1. #include <stdio.h> 
  2. #include <string.h> 
  3.  
  4.  
  5. int 
  6. do_match(const char *var) 
  7.   char *range1   = "12345"; 
  8.   char *range2   = "0123456789"; 
  9.   char *pat      = " settembre 20"; 
  10.   int pat_len    = strlen(pat); 
  11.   int i          = 0; 
  12.   int len        = strlen(var); 
  13.   int match      = 0; 
  14.  
  15.   for (i = 0; i < len && !match; i++) { 
  16.     /* [1-5] */ 
  17.     if (strchr(range1, var[i]) != NULL) { 
  18.       /* " settembre 20" */ 
  19.       if (strncmp(var + 1, pat, pat_len) == 0) { 
  20.         /* [0-9][0-9] */ 
  21.         match = strchr(range2, var[i + pat_len + 1]) != NULL && 
  22.           strchr(range2, var[i + pat_len + 2]) != NULL; 
  23.       } 
  24.     } 
  25.   } 
  26.  
  27.   return match; 
  28.  
  29.  
  30. int 
  31. main(int argc, char *argv[]) 
  32.   int i; 
  33.    
  34.   for (i = 1; i < argc; i++) 
  35.     printf("'%s' %d\n", argv[i], do_match(argv[i])); 
  36.  
  37.   return 0; 
Il codice marcato in grassetto equivale alla regex del programma in perl precedente. È più che evidente che il controllo di correttezza su un algoritmo di matching ad hoc è più complesso della lettura ed interpretazione dei formalismi di una regex.

Quando NON conviene usarle?

Le regex devono essere interpretate, ciò comporta l'uso di una certa quantità di spazio (memoria) e tempo.
Per problemi di matching molto semplici è inutile e dispendioso l'utilizzo di una regular expression dove una strcmp o una memcmp (nel caso di C) possono fare gran parte del lavoro in maniera più efficiente.

Conclusioni

Questa prima parte sulle Regular Expressions termina qui, nel prossimo articolo verranno presi in considerazione vari linguaggi ed il modo in cui le regex sono implementate e la loro integrazione con il linguaggio ospite.

Informazioni sull'autore

Marco Lamberto, laureato in Informatica presso la Statale di Milano, con diversi anni di esperienza sistemistica, di sicurezza e sviluppo prevalentemente in ambienti UNIX (Linux in primis) con linguaggi come C, Java, Perl, PHP, XML, HTML, ...

È possibile consultare l'elenco degli articoli scritti da Marco Lamberto.

Altri articoli sul tema Linguaggi / Regular Expressions.

Risorse

  1. "Mastering Regular Expressions" è una lettura obbligatoria per chiunque volesse approfondire all'estremo la conoscenza delle RegEx (features avanzate, limitazioni, ottimizzazioni) facendo molta attenzione alle loro implementazioni specifiche.
    http://www.oreilly.com/catalog/regex/
  2. Man page del perl sulle regular expressions. Suggerita la lettura anche di "perlrequick" e "perlretut", i riferimenti possono essere trovati in fondo al documento nella sezione "SEE ALSO".
    http://www.perldoc.com/perl5.8.0/pod/perlre.html
  3. Api reference sul package Java2 "java.util.regex".
    http://java.sun.com/j2se/1.4.1/docs/api/java/util/regex/package-summary.html
  4. Questo è il manuale della libreria GNU delle Regular Expression scritta in C ed integrata in diversi progetti e linguaggi.
    http://docs.freebsd.org/info/regex/regex.info.Top.html
  5. Pagina del manuale di PHP sulle funzioni che implementano le regular expressions in stile Perl.
    http://www.php.net/manual/en/ref.pcre.php
  6. Pagina del manuale di PHP sulle funzioni che implementano le regular expressions in stile POSIX Extended.
    http://www.php.net/manual/en/ref.regex.php
Discuti sul forum   Stampa

Cosa ne pensi di questo articolo?

Discussioni

Questo articolo o l'argomento ti ha interessato? Parliamone.