mercoledì 19 dicembre 2012

Espressioni regolari (RegExp)


Espressioni regolari

La sintassi delle espressioni regolari è considerata superata dallo standard POSIX, ma è comunque molto usata per la sua larga diffusione. La maggior parte dei programmi che utilizzano le regexp, utilizzano queste regole dando anche il supporto per le nuove regole che sono più estese.
Questi sono i  "metacaratteri" che ci permetteranno di effettuare le espressioni di ricerca:
.
Trova un singolo carattere (se è nella modalità linea singola altrimenti se è in multiriga prende tutti i caratteri diversi da \n, ovvero un ritorno a capo).
[ ]
Trova un singolo carattere contenuto nelle parentesi. Ad esempio, [abc] trova o una "a", "b", o "c". [a-z] è un intervallo e trova ogni lettera minuscola dell'alfabeto. Possono esserci casi misti: [abcq-z] trova a, b, c, q, r, s, t, u, v, w, x, y, z, esattamente come [a-cq-z].
Il carattere '-' è letterale solo se è primo o ultimo carattere nelle parentesi: [abc-] o [-abc]. Per trovare un carattere '[' o ']', il modo più semplice è metterli primi all'interno delle parentesi: [][ab] trova ']', '[', 'a' o 'b'.
[^ ]
Trova ogni singolo carattere non incluso nelle parentesi. Ad esempio, [^abc] trova ogni carattere diverso da "a", "b", o "c". [^a-z] trova ogni singolo carattere che non sia una lettera minuscola. Come sopra, questi due metodi possono essere usati insieme.
^
Corrisponde all'inizio della stringa (o di ogni riga della stringa, quando usato in modalità multilinea)
$
Corrisponde alla fine della stringa o alla posizione immediatamente precedente un carattere di nuova linea (o alla fine di ogni riga della stringa, quando usato in modalità multilinea)
( )
Definisce una "sottoespressione marcata". Il risultato di ciò che è incluso nell'espressione, può essere richiamato in seguito. Vedi sotto, \n.
\n
Dove n è una cifra da 1 a 9; trova ciò che la nesima sottoespressione ha trovato. Tale costrutto, detto backreference, estende le potenzialità delle regexp oltre i linguaggi regolari e non è stato adottato nella sintassi estesa delle regexp.
*
  • Un'espressione costituita da un singolo carattere seguito da "*", trova zero o più copie di tale espressione. Ad esempio, "[xyz]*" trova "", "x", "y", "zx", "zyx", e così via.
  • \n*, dove n è una cifra da 1 a 9, trova zero o più iterazioni di ciò che la nesima sottoespressione ha trovato. Ad esempio, "(a.)c\1*" trova "abcab" e "accac" ma non "abcac".
  • Un'espressione racchiusa tra "\(" e "\)" seguita da "*" non è valida. In alcuni casi (es. /usr/bin/xpg4/grep di SunOS 5.8), trova zero o più ripetizioni della stringa che l'espressione racchiusa ha trovato. In altri casi (es. /usr/bin/grep di SunOS 5.8), trova ciò che l'espressione racchiusa ha trovato, seguita da un letterale "*".
{x,y}
Trova l'ultimo "blocco" almeno x volte e non più di y volte. Ad esempio, "a{3,5}" trova "aaa", "aaaa" o "aaaaa".
Vecchie versioni di grep non supportano il separatore alternativo "|".
Esempi:
".atto" trova ogni stringa di cinque caratteri come gatto, matto o patto
"[gm]atto" trova gatto e matto
"[^p]atto" trova tutte le combinazioni dell'espressione ".atto" tranne patto
"^[gm]atto" trova gatto e matto ma solo all'inizio di una riga
"[gm]atto$" trova gatto e matto ma solo alla fine di una riga
Dal momento che molte serie di caratteri variano a seconda della configurazione locale (in alcuni casi le lettere sono organizzate in abc..xyzABC...XYZ, in altri aAbB..yYzZ), lo standard POSIX ha definito alcune classi o categorie di caratteri come mostrato nella seguente tabella:
classe POSIX
sintassi normale
significato
[:upper:]
[A-Z]
lettere maiuscole
[:lower:]
[a-z]
lettere minuscole
[:alpha:]
[A-Za-z]
lettera sia maiuscole che minuscole
[:alnum:]
[A-Za-z0-9]
numeri e lettere maiuscole e minuscole
[:digit:]
[0-9]
numeri
[:xdigit:]
[0-9A-Fa-f]
numeri in formato esadecimale
[:punct:]
[.,!?:...]
segni di interpunzione
[:blank:]
[ \t]
spazio o TAB
[:space:]
[ \t\n\r\f\v]
caratteri vuoti
[:cntrl:]

caratteri control
[:graph:]
[^ \t\n\r\f\v]
caratteri non vuoti
[:print:]
[^\t\n\r\f\v]
caratteri non vuoti e spazi

Le parentesi quadrate fanno parte della sintassi per indicare la classe di caratteri. Ad esempio [[:upper:][:digit:]ab] trova corrispondenza in una qualsiasi lettera maiuscola, in una qualsiasi cifra, nella lettera 'a' minuscola e nella lettera 'b' minuscola.
Esempi di quantificatori
  • * Cerca l'occorrenza (zero o più volte) del carattere o insieme di caratteri cui segue:
abc* identifica ab seguito da zero o più c
come in ab, abc, abcc, abccc
  • + Cerca l'occorrenza (una o più volte) del carattere o insieme di caratteri cui segue:
ab[ce]+ identifica ab seguito da una o più c oppure una o più e
come in abc, abec, abccc, abcceeecccccce
  • ? Cerca l'occorrenza (zero o una volta) del carattere o insieme di caratteri cui segue:
abc? identifica ab seguito o meno da una c
come in abc e ab
  • {m, n} Cerca l'occorrenza (da m a n volte; m lasciato vuoto è zero, n lasciato vuoto infinito) del carattere, insieme di caratteri o sotto-regex cui segue:
(ab){1,2} identifica le sequenze di uno o due ab
come in ab e abab

mercoledì 12 dicembre 2012

Codice catastale di un comune Italiano

Qui potete visualizzare uno script in php per la ricerca del codice del comune, e il risultato che vi apparirà sarà il nome del comune, il suo codice, e la sigla della provincia:




Per l'elenco dei comuni ho creato un normale file di testo che incorporo con il codice:

<?php
    $pattern="/".$_POST[comune]."/i";
    //apre il file:
    $comuni=fopen("../inc/codici_catastali_comuni.txt","r");
    $i=0;
    if($_POST[comune]!=""){
        while (!feof($comuni)) {
            //ottiene riga per riga il file e lo asegna a buffer:
            $buffer = fgets($comuni, 4096);
            //se incontra i parametri di ricerca, inserisci un
            // nuovo valore al contenuto dell'array "stringa":
            if(preg_match($pattern,$buffer)){
                $stringa[$i]=$buffer;
                $i++;
            }
        }
        #chiude il file:
        fclose ($comuni);
    }
?>

UN PICCOLO APPUNTO:

Questa versione del programma è solo dimostrativa, in quanto questo codice non è perfetto, infatti, se mettiamo il nome di un comune che è simile ad un altro (es. Como e Zibido San Giacomo) il sistema prenderà l'ultimo in elenco corrispondente alla ricerca. Va quindi perfezionato, ma per lo scopo dimostrativo che ha per il momento è sufficiente per capire come ciclare il contenuto di un file riga per riga senza caricarlo tutto in memoria, a prescindere dalla sua dimensione. questa funzione, denominata fgets(), sarà utile quando su web, dove le risorse sono sempre "risicate", dovremo controllare file di grandi dimensioni.

Update: 17/12/2012

Effettuata la modifica del programmino, per avere un elenco ordinato in base alle occorrenze trovate. Inserire questo codice nel programma diventa così un lavoro piuttosto semplice dando la possibilità di inserire i dati corretti suggerendoli direttamente all'utente.


Questo è il codice per il risultato ciclato secondo il suo ordine alfabetico
(n.b.: è ordinato alfabeticamente il file, e quindi anche il suo risultato. Il file viene ciclato riga per riga, restituendo per ultimo l'ultima riga del file, a prescindere se esiste un ordine o meno. er ordinare comunque un array in php ci sono delle funzioni per le quali rimando al manuale. v. Man. Php Ita - Array Sort)

<?php
$y=1;
for($x=0;$x<count($stringa);$x++){
    $array=explode(" ",$stringa[$x],2);
    $codiceComune=$array[0];
    $nomeComune=substr($array[1],0,-6);
    $siglaProvincia=substr($stringa[$x], -4, 2); // Es MI
    print "<br>Risultato $y di $i:<br>Codice Comune: $codiceComune<br>Comune: $nomeComune<br>Provincia: $siglaProvincia<br>";
    $y++;
}
?>

Sviluppo di un programma passo-passo - Parte 1

CALCOLO DEL CODICE FISCALE E BASI DELLA PROGRAMMAZIONE


Ciao a tutti! Dopo la pausa decisionale per scegliere il progetto da fare, siamo giunti ad una nuova idea, che esiste certamente, in tutte le salse: il calcolo del codice fiscale. Cliccando su questo link, troverete una pagina molto ben spiegata nel quale troverete le regole per creare l'algoritmo che genera il famoso codice che ci rende tutti univoci al dipartimento dell'agenzia delle entrate!



Resta però da definire in quale linguaggio scrivere l'applicazione che calcolerà il codice fiscale, e il perchè. Vogliamo rendere un servizio al'utente, o vogliamo fare un supercontrollo all'invio di un form? Oppure ancora, vogliamo fare un controllo incrociato  dei dati di un db, e segnalare quali incongruenze ci sono e inviare statistiche sulla clientela controllata, o magari, un semplice esercizio scolastico?

Le possibilità sono diverse, e in base allo scopo si dovrebbe scegliere cosa fare. In un libro sul C++ acquistato nel lontano 1999, edito da Apogeo "C++ Tutto & Oltre" di Jesse Liberty, c'è una fondamentale quanto semplice mappa concettuale sul ciclo di progettazione-realizzazione di un programma:
  1. Concettualizzazione
  2. Analisi
  3. Progettazione
  4. Implementazione
  5. Test
  6. Produzione
Tutto questo verrà spiegato passo-passo durante la realizzazione del programma sul codice fiscale. Per il momento, possiamo però partire dal primo punto. Partiamo quindi dalla Concettualizzazione,  ovvero l'INTUIZIONE. Certo, convengo con voi per il fatto che c'è poco da intuire su un programma che è già stato fatto in molti modi diversi, ma anche in questo caso possiamo fare un cenno su cosa sia la concettualizzazione e usarla per iniziare finalmente questo progetto.

CONCETTUALIZZAZIONE

L'intuizione è quella fase in cui si determina lo scopo del nostro programma (nel libro si riferisce alla programmazione a oggetti, ma io sono convinto che questi passi possono essere seguiti per qualsiasi tipo di programmazione, anche futura), un momento brevissimo che getterà le fondamenta su ciò che verrà fatto. Potrà certamente essere aggiornata mano a mano che sviluppa il nostro software, in base a determinate esigenze e nuove idee. In un team di sviluppo potrebbe esserci anche una persona designata allo scopo di proteggere e aggiornare l'idea e controllare che tutto ciò che ne segue venga fatto seguendo l'intuizione originale. Può essere una frase, un paragrafo, o un'idea che descrive brevemente ma in modo dettagliato cosa dovrà fare il nostro progetto e perchè. Il rispondere ad una delle domande che scrivevo poco sopra ad esempio potrebbe essere un buon inizio per questa fase d'intuizione.
Bene, ma allora cosa vogliamo fare con questo algoritmo che già esiste? Semplice. L'idea di sviluppo di questo algoritmo sarà "creare un programma che sarà disponibile alla consultazione online, registrerà un log di utilizzo, memorizzerà i dati ricercati in un db, invierà il risultato via mail o sarà pronto per essere stampato". La ricerca consisterà nel calcolo del codice fornendo i dati della persona, tenendo presente che comunque ci sono alcune variazioni che solo il ministero può decidere e che non sono conosciute a noi comuni mortali! L'esempio più calzante, è che in caso di forte omonimia prevista dal decreto legge, si faccia ciò che viene descritto nell'articolo 6 del D.M. n° 345 del 23/12/1976, che non possiamo fare dall'esterno, ma solo emularlo, in quanto non possiamo avere a disposizione l'intero archivio del C.F. registrato in Italia.

CONCLUSIONE

Bene, ci siamo!
Con questo primo passo abbiamo dato il via al nostro programma. Non abbiamo ancora scritto una riga di codice e alcune ricerche dovranno esser fatte, ma questa sarà la parte di Analisi che non è altro che il secondo passo relativo alla programmazione. Effettivamente, quando si parla di scrivere un programma, la scrittura del codice che poi eseguirà il programma è solo uno dei 6 passi descritti sopra. Questa è l'informatica, ovvero la gestione automatica delle informazioni che senza un preciso scopo, un'analisi e molti test anche prima di scrivere il codice di un programma, non avrebbe molto senso chiamarla così.

Stampa