-+  Documenti
 |-  Bibliografia
 |-  Articoli
 |-  Perlfunc
 |-  F.A.Q.
 |-  F.A.Q. iclp
-+  Eventi
-+  Contatti
-+  Blog
-+  Link



 

Versione stampabile.


Michele Beltrame
Michele Beltrame vive a Maniago, PN, è programmatore Perl e convinto sostenitore del movimento Open Source. PuĂò essere raggiunto via e-mail all'indirizzo arthas@perl.it

Data di pubblicazione: Questo articolo è stato pubblicato su Dev n°84 e in questo sito per autorizzazione espressa del "Gruppo Editoriale Infomedia" (http://www.infomedia.it).

© 2007 Michele Beltrame.

1. Introduzione 

2. Gestione di stringhe 

3. Matematica 

4. Data ed ora 

5. Conclusioni 

Introduzione

Una delle caratteristiche salienti di Perl è il numero di funzioni disponibili senza che sia necessario ricorrere a moduli. Data una qualunque operazione da fare, difficilmente sarà necessario scrivere molto codice: nella maggior parte dei casi poche righe saranno sufficienti. Questo rende il linguaggio diverso da alcuni suoi colleghi più a basso livello, ma da esso eredita comunque molto, quali il C. Se infatti dobbiamo ordinare un array, in C sarà necessario studiarsi l'algoritmo (cosa che comunque non fa mai male, visto che pochi programmatori sembrano sapere come si effettua un mergesort oppure un quicksort) ed implementare una nostra funzione, o al più ricorrere a qualche libreria esterna. Perl mette invece a disposizione la funzione sort(), che automaticamente effettua un quicksort su una lista secondo i parametri passati. Vi sono molti altri esempi in cui Perl offre delle "scorciatoie", ed in questo articolo ne vedremo alcuni. Il fatto che una funzione sia più o meno utile naturalmente dipende dalle esigenze del singolo programmatore, che è quindi invitato a dare una rapida occhiata a tutte quelle che il linguaggio include.

 Gestione di stringhe

Una funzione di uso molto comune nel mondo delle stringhe è chop(). Il suo scopo è semplicemente quello di tagliare l'ultimo carattere della stringa passata come argomento, e solitamente viene utilizzata per rimuovere il newline (\n) posto al termine. Se ad esempio leggiamo, come visto nella scorsa lezione, un file riga per riga, ci troviamo ad avere una serie di stringhe terminate da newline, carattere di cui potremmo volerci sbarazzare. Scriveremmo quindi:

$c = chop($a);

Come si nota, la funzione ha anche un valore di ritorno, che è il carattere tagliato. È fondamentale notare che chop() rimuove l'ultimo carattere qualunque esso sia, quindi se per caso manca il newline, verrà tagliato l'ultimo carattere valido. C'è tuttavia l'alternativa intelligente: chomp(). Questa rimuove l'ultimo carattere solo se è un newline, altrimenti non ha effetto; inoltre, se i newline sono più di uno, li rimuove tutti e ritorna il numero di caratteri tagliati. La coppia join() e split() permette, abbastanza prevedibilmente, rispettivamente di unire o separare stringhe basandosi su un'espressione. Vediamo subito un esempio:

@a = ('Michele', 'Andrea', 'Anna', 'Luca');
$tutti = join '_', @a;

$tutti contiene Michele_Andrea_Anna_Luca, cioè tutti gli elementi della lista uniti tra loro e separati da un underscore. Esattamente il contrario fa split(): ponendo di avere a disposizione la stringa $tutti appena creata, possiamo ottenere di nuovo le singole parti con:

@a = split /_/, $tutti;

Come si vede, in questo caso il primo parametro, anziché una semplice stringa come in join(), è un pattern: questo rendere possibile effettuare separazioni sulla base di regular expression, e quindi anche ad esempio considerando più di un carattere come separatore. Infatti:

split /[_,;]/, $tutti;

considera separatori sia l'underscore che la virgola che il punto e virgola. Simili a join() e split(), ma solo per il fatto che uniscono e separano dati, sono pack() ed unpack(). Queste sono funzioni di straordinaria potenza che, tra le altre cose, permettono di unire una lista in una stringa di lunghezza fissa: non vi sono cioè dei separatori ma un numero di caratteri fisso che determina quando finisce una parte ed inizia l'altra. Vediamo un esempio che utilizza lo stesso array @a di cui prima:

$string = pack ("A60A20A15A50", @a);

Il risultato è una stringa di ben 145 caratteri contenente i quattro elementi dell'array in uno schema fisso: il primo occupa 60 caratteri, il secondo 20, il terzo 15 ed il quarto 50. Visto che sono tutti più corti rispetto alla lunghezza dichiarata, il carattere A fa si che a destra vengano inseriti degli spazi. Dovesse uno degli elementi superare la lunghezza dichiarata, la parte di esso che non sta verrebbe troncata. Tramite unpack() si fa l'esatto contrario:

@a = unpack ("A60A20A15A50", $string);

La funzione più importante di pack() ed unpack() non è tuttavia questa appena vista, ma quella di permettere l'accesso a file dal contenuto binario (ad esempio numeri memorizzati come tali, e non come stringhe). Chiunque fosse interessato ad accedere a questo tipo di file, troverà queste funzioni indispensabili. A volte può essere necessario creare un output un po' più "curato" di quanto print() permette. Allo scopo sono disponibili la funzione write() ed i formati, che però qui non analizziamo, ma ci limitiamo a citare in modo che il lettore interessato sappia della loro esistenza. Essi permettono di creare un output completamente formattato, gestibile in ogni suo aspetto. Vediamo invece funzioni di uso più generale, ed in particolare printf() e sprintf(). Chi conosce almeno i rudimenti della programmazione in C le ha sicuramente già incontrate, in quanto fondamentali per gestire l'input/output in tale linguaggio. Probabilmente anche chi programma in C++ le ha incontrare almeno qualche volta, benché in quest'ultimo linguaggio esse siano state di fatto sostituite dallo stream cout. printf() crea e stampa una stringa formattata dati i parametri di formattazione e la lista di cosa va stampato. Se ad esempio vogliamo visualizzare un numero accertandoci che sia arrotondato alla seconda cifra decimale, scriviamo:

printf "Il numero è: %.2f", $num;

Se $num è 2.432874, esso verrà visualizzato come 2.43; di contro, se è semplicemente 2, verrà visualizzato come 2.00. Così come i numeri in virgola mobile, è possibile formattare qualsiasi altro tipo di dato, secondo i formati riportati in Tabella 1

Carattere Descrizione
%%
Segno di percentuale
%c
Carattere corrispondente al numero indicato
%s
Stringa
%d
Intero decimale con segno
%u
Intero decimale senza segno
%o
Intero ottale senza segno
%x
Intero esadecimale senza segno
%b
Intero binario senza segno
%e
Numero in virgola mobile, notazione scientifica
%f
Numero in virgola mobile, notazione decimale fissa
%g
Numero in virgola mobile, notazione scientifica o decimale fissa
%X
Come %x, ma con lettere maiuscole
%E
Come %e, ma con la E maiuscola
%G
Come %g, ma con la E maiuscola (se presente)
%p
Puntatore (indirizzo in esadecimale)
%n
Memorizza il numero di caratteri stampati finora nella variabile passata come argomento

ed i flag visibili in Tabella 2.

Flag Descrizione
spazio
Mette uno spazio prima di un numero positivo
+
Mette un + prima di un numero positivo
-
Giustifica il campo a sinistra
0
Usa zeri anziché spazi per giustificare a destra
#
Mette uno 0 prima di un ottale diverso da zero, o uno 0x prima di un esadecimale diverso da zero
num
Lunghezza minima del campo
.num
Per gli interi: lunghezza minima. Per le stringhe: lunghezza massima. Per i decimali: cifre dopo la virgola
l
Considera l'intero un long o unsigned long come in C
h
Considera l'intero un short o unsigned short come in C (senza flag considera int o unsigned int)

In questo caso il formato è f, ed è stato utilizzato il flag .numero per stabilire quante cifre dopo la virgola andassero stampate. sprintf() è identica a printf(), solo che anziché stampare la stringa creata, la ritorna:

$a = sprintf "Il numero è: %.2f", $num;

Il tipico "re dell'officina" per quanto riguarda la gestione delle stringhe è substr(). Questa funzione rende possibile tutta una serie di operazioni, le quali sostanzialmente permettono, come il nome della funzione lascia intuire, di gestire le parti, i singoli caratteri, di una stringa. Vediamo brevemente alcuni esempi del suo utilizzo:

# Taglia l'ultimo carattere (come chop())
substr($a, -1, 1) = '';
# Ritorna il terzo e quarto carattere
$b = substr($a, 2, 2);
# Sostituisce il primo carattere con "casa"
substr ($a, 0, 1) = "casa";

Come si vede gli impieghi possibili sono molteplici, e la funzione si occupa automaticamente di ridimensionare la stringa quando necessario. I parametri da passare a substr() sono il nome della variabile contenente la stringa, l'offset al quale si desidera iniziare a leggere o scrivere ed il numero di caratteri da prendere in considerazione. Un offset negativo indica di partire dalla fine della stringa, mentre un numero di caratteri negativo indica di considerare l'intera stringa a partire dall'offset lasciando però da parte quel numero di caratteri alla fine della stringa.
L'ultima e semplicissima funzione che analizziamo per quanto riguarda la gestione delle stringhe è length(), che ritorna il numero di caratteri di cui una stringa è composta:

$n = length $a;

 Matematica

Le funzioni matematiche messe a disposizione da Perl senza che sia necessario ricorrere a strumenti esterni sono quelle classiche, reperibili più o meno in tutti i linguaggi. Iniziamo discutendo il problema degli arrotondamenti. Esiste la funzione int(), che però non fa quello che molti credono: essa non arrotonda, ma semplicemente tronca la parte decimale di un numero. Per arrotondare è necessario utilizzare sprintf(). Ad esempio:

$inum = sprintf "%.0f", $num;

calza a pennello. Il carattere di formato f si occupa di arrotondare il numero decimale all'intero, approssimazione che avverrà per eccesso o per difetto a seconda del caso. Allo stesso modo è consentito arrotondare fino ad una cifra decimale a piacere, ad esempio la quarta, con:

$inum = sprintf "%.4f", $num;

Anche in questo caso è sprintf() a stabilire quando arrotondare per eccesso e quando per difetto. Le funzioni trigonometriche sono sin() e cos(), che ritornato seno e coseno: tramite esse si può ad esempio ricavare, ricordando l'apposita e semplice relazione, la tangente. Esiste inoltre atan2(), che calcola l'arcotangente. Non c'è una funzione che ritorni Π, però una sua buona approssimazione la si ottiene con:

$pi = atan2(1,1) * 4;

Un'altra esigenza comune è quella di creare dei numeri casuali (random). La funzione rand() permette ciò, ad esempio:

$n = rand 5;

torna un numero in virgola mobile tra 0 e 5 (estremo inferiore incluso, estremo superiore escluso). Se non viene passato alcun parametro il numero tornato varia tra 0 ed 1, sempre escludendo l'estremo superiore. Per creare un numero casuale intero ad esempio incluso tra 1 e 20 si può quindi scrivere:

$n = int(rand  20) + 1;

Questa funzione richiama quelle di sistema per la creazione di numeri casuali, e quindi la casualità dipende da come queste ultime sono implementare. Per i casi generali essa è tuttavia sufficientemente "casuale". Una nota: in versioni di Perl precedenti alla 5.004 il seed dei numeri random non veniva inizializzato automaticamente. Se il proprio interprete è piuttosto vecchio, sarà necessario chiamare srand() all'inizio del proprio programma, una volta sola.
I moduli appartenenti al settore Math, ad esempio Math::Trig e Math::Complex permettono di effettuare qualsiasi tipo di calcolo semplicemente chiamando l'apposita funzione, e rendendo quindi semplice calcolare ad esempio seno iperbolico, secante e via dicendo, nonché effettuare conversioni e lavorare con i numeri complessi e gli interi molto grandi. Vi sono inoltre librerie che permettono di creare numeri veramente casuali (o almeno un po' più casuali). Ancora non si è tuttavia visto come utilizzare un modulo esterno, cosa che sarà argomento della prossima lezione.

 Data ed ora

È di fondamentale importanza poter gestire la data e l'ora, rendendone possibile la visualizzazione in vari formati. In Perl vi sono alcune funzioni che permettono di fare tutto ciò in maniera semplice e personalizzabile: esse sono time(), gmtime() e localtime(). La prima ritorna una Unix-style timestamp contenente il numero di secondi trascorsi dall'Epoch (1 Gennaio 1970, 00:00), valore dal quale è possibile ottenere tutto il resto. Infatti localtime() accetta come parametro uno di questi interi, chiamando automaticamente time() nel caso nessun parametro sia passato, e restituisce un array:

@ltime = localtime($ora);

L'array è composto come si vede in Tabella 3.

Flag Descrizione
0
Numero di secondi (0-60)
1
Numero di minuti (0-59)
2
Numero di ore (0-23)
3
Giorno del mese (1-31)
4
Mese dell'anno (0-11)
5
Anno (a partire dal 1900, quindi il valore di reale interesse è 1900+Anno)
6
Giorno della settima (0-6, 0 è Lunedì)
7
Giorno dell'anno (1-366)
8
Ora legale (true se è attiva)

È dunque possibile estrarre qualsiasi informazione in maniera molto semplice, e formattare data ed ora a piacere con dei semplici print() o printf(). Vediamo qualche esempio:

# Estrae il minuto attuale
$min = (localtime)[1];
# Estrae il giorno della settimana a tre lettere
$oggi = (Dom,Lun,Mar,Mer,Gio,Ven,Sab)[(localtime)[6]];
# Estrae l'anno
$anno = 1900+(localtime)[5];

gmtime() è uguale a localtime(), con l'unica differenza che, mentre la seconda torna l'ora locale, la prima la restituisce in Universal Time (ex GMT). L'utilizzo della Unix-style timestamp può sembrare a prima vista una scelta bizzarra ed in prima battuta si tende magari ad evitarlo preferendo sempre localtime() o gmtime(). In realtà la timestamp è piuttosto comoda, in quanto permette di effettuare calcoli sull'ora utilizzando l'aritmetica tradizionale. Ad esempio per verificare che una variabile contenga una data non anteriore a 24 ore fa possiamo scrivere, tenendo conto che in un giorno ci sono 86400 secondi:

if ($data >= (time()-86400) {
  # Codice
}

Per memorizzare in una variabile la stessa ora di oggi, ma avanti di sette giorni è invece possibile utilizzare:

$futuro = time() + 604800;

Anche qui le possibilità, ricorrendo ai moduli, sono notevolmente superiori. In particolare è possibile costruire una timestamp a partire dai singoli valori.

 Conclusioni

In questa lezione si sono analizzate le funzioni principali offerte da Perl per quanto riguarda la gestione di stringhe, numeri e date. Per quanto riguarda settori diversi, ve ne sono naturalmente molte altre: una parte di essere verrà illustrata nella prossima lezione, le rimanenti sono lasciate allo studio individuale. Inoltre, come già accennato un paio di volte in precedenza, utilizzando dei moduli esterni (molti dei quali sono peraltro già inclusi nella distribuzione standard dell'interprete perl) si possono compiere operazioni ancora diverse, oppure le stesse in maniera più efficiente. Nella prossima puntata vedremo brevemente anche come fare per servirsi di tali moduli.

  1. Larry Wall, Tom Christiansen, Jon Orwant - "Programming Perl (3rd edition)", O'Reilly & Associates, Luglio 2000
  2. Tom Christiansen, Nathan Torkington - "Perl Cookbook", O'Reilly & Associates, Settembre 1998


Ti è piaciuto questo articolo? Iscriviti al feed!











Devo ricordare i dati personali?






D:
Annunci Google