In Perl, a differenza di quanto accade con altri linguaggi di programmazione, non è necessario dichiarare le variabili prima di utilizzarle; il simbolo '$' che le precede sta ad indicare che si tratta di variabili che possono accettare un unico valore, che potrà essere un numero, un singolo carattere o una stringa. Chiameremo questo tipo di variabili scalari, per distinguerle da altri tipi più complessi (variabili vettoriali).
L'interprete Perl, utilizzando le variabili nelle istruzioni del nostro programma, stabilirà dal contesto se queste devono essere utilizzate come variabili numeriche o come stringhe.
$nome = 'Marco'; | stringa |
$n = 3; | numero intero |
$x = 3.1415; | numero razionale |
$saluto = "Ciao $nome\n"; | stringa con interpolazione |
$giorno = `date`; | comando |
Un array è una struttura dati che permette di accedere ad un set di variabili scalari direttamente attraverso un indice numerico; potremmo dire, in altri termini, che si tratta di una variabile a più componenti.
I nomi degli array in Perl sono preceduti dal simbolo '@' per distinguerli dalle variabili scalari. Le singole componenti del vettore (array) sono delle variabili scalari. Ad esempio l'istruzione
@frutta = ('mele', 'pere', 'banane', 'uva'); |
definisce l'array @frutta come un vettore a quattro componenti; per accedere alla singola componente si deve usare un indice numerico, come nel seguente esempio:
#!/usr/local/bin/perl # script "frutta.pl" @frutta = ('mele', 'pere', 'banane', 'uva'); print "un cesto pieno di $frutta[1].\n"; |
Il primo elemento di un vettore in Perl ha indice 0, quindi se un vettore ha n elementi, l'ultimo elemento ha indice n-1. Ad esempio lo script precedente fornisce il seguente risultato:
$ frutta.pl un cesto pieno di pere. $ |
Può essere interessante osservare come sia possibile utilizzare gli array nel trattamento di file di testo. A seconda dei casi, e soprattutto in funzione della dimensione del file da leggere, può essere opportuno leggere il file una riga per volta, assegnando la riga letta ad una variabile scalare, ovvero leggere il file per intero, assegnando ogni riga del file ad un elemento di un array di stringhe.
#!/usr/local/bin/perl # leggi.pl # legge i dati dallo standard input una riga per volta # e li stampa $i = 0; while ($riga = <STDIN>) { $i++; print "$i) $riga"; } |
#!/usr/local/bin/perl # leggi_2.pl # legge i dati dallo standard input per intero # e poi li stampa @riga = <STDIN>; for ($i=0; $i<=$#riga; $i++) { print "$i) $riga[$i]"; } |
Nel primo esempio (leggi.pl) il file viene letto una riga alla volta ed immediatamente stampata; viene quindi fatto un uso limitato della memoria della macchina, ma non è possibile utilizzare in seguito le righe del file lette ai passi precedenti. Viceversa nel secondo esempio (leggi_2.pl) il file viene caricato in memoria per intero, assegnando ad ogni componente dell'array @riga una linea del file di testo; successivamente le linee vengono stampate (facendo uso della struttura di controllo for che introdurremo in seguito). In questo caso il programma può utilizzare in qualsiasi momento ogni linea del file, senza doverla rileggere; tuttavia se il file è di grosse dimensioni, viene fatto un uso pesante della memoria della macchina.
L'espressione '$#riga' fornisce l'indice dell'ultima componente dell'array @riga.
Una lista in Perl è semplicemente un insieme ordinato di scalari. Una lista può contenere numeri, stringhe o anche un misto di entrambi questi tipi di dato. In effetti in Perl la differenza tra una lista ed un array è molto sottile, tanto che potremmo dire che se assegnamo un nome ad una lista ciò che otteniamo è un array. Più che altro la distinzione, ben marcata in altri linguaggi di programmazione, in Perl riguarda soprattutto il modo in cui vengono utilizzati certi insiemi di dati.
Una lista viene definita elencandone gli elementi, come, ad esempio:
('cani', 'gatti', 'cavalli', 'pesci') (1, 2, 3, 4, 5, 47, 1.34, 12) |
Come abbiamo già visto possiamo inizializzare un array con il contenuto di una lista con la seguente istruzione:
@animali = ('cani', 'gatti', 'cavalli', 'pesci'); |
Gli elementi di una lista possono essere ordinati alfabeticamente utilizzando l'istruzione sort; ad esempio, la seguente istruzione ci permette di ordinare il contenuto dell'array @animali appena definito:
@animali = sort @animali; |
Cogliamo l'occasione per elencare tre importanti istruzioni che consentono di effettuare delle operazioni elementari sulle liste. L'istruzione shift restituisce il primo elemento della lista e lo elimina dalla lista stessa. L'operatore pop restituisce invece l'ultimo elemento della lista e lo elimina dalla lista. Infine l'operatore push inserisce un elemento al termine della lista.
Veniamo ora al tipo di dato più importante in Perl, gli array associativi; citando Larry Wall (l'autore del Perl) si può dire che se non si pensa in termini di array associativi non si sta pensando in Perl.
Un normale array ci permette di 'puntare' ai suoi elementi usando numeri interi come indici. Un array associativo ci permette di fare la stessa cosa utilizzando delle stringhe come indici (o chiavi, in questo caso). Visto che spesso gli elementi dell'array sono stringhe, in questo modo possiamo associare tra loro coppie di stringhe: il dato vero e proprio e la chiave (o l'indice) che lo identifica all'interno dell'array.
Un array associativo è una lista di valori come ogni altro array, salvo che per il fatto che invece di indicizzare l'array mediante la posizione di ogni elemento, si indicizza ogni coppia di valori dell'array mediante il primo elemento della coppia.
Ad esempio supponiamo di voler tenere conto del numero di giorni di ogni mese dell'anno (supponiamo anche di non essere in un anno bisestile); il seguente programmino potrebbe aiutarci:
#!/usr/local/bin/perl # giorni.pl: dato il nome di un mese ne stampa il # numero di giorni %giorni = ('gennaio', 31, 'febbraio', 28, 'marzo', 31, 'aprile', 30, 'maggio', 31, 'giugno', 30, 'luglio', 31, 'agosto', 31, 'settembre', 30, 'ottobre', 31, 'novembre', 30, 'dicembre', 31); print "mese: "; $mese = <STDIN>; chop($mese); print "$mese ha $giorni{$mese} giorni.\n"; |
In maggiore dettaglio possiamo dire che ci si riferisce ad un array associativo con il simbolo '%' (e non con la chiocciola '@', come per i normali array o le liste); il singolo elemento dell'array associativo (che, come al solito è uno scalare) è individuato dalla chiave associata; così il terzo elemento dell'array associativo definito nell'esempio precedente (31, il numero di giorni del mese di marzo) è individuato dall'espressione $giorni{'marzo'}.
La funzione chop usata dopo aver letto un input da file, serve ad eliminare il carattere di fine riga dalla variabile che contiene l'input (nel nostro caso la variabile $mese).
Osserviamo infine che la funzione keys() restituisce una lista con le chiavi dell'array associativo passato come argomento, in modo da consentirci di operare sugli elementi dell'array nell'ordine desiderato. La funzione values() effettua l'operazione complementare: restituisce una lista con i valori degli elementi dell'array associativo passato come argomento.
Il Perl adotta in pieno la convenzione sull'uso degli apici, già adottata da numerosi altri tool in ambiente UNIX, tanto da rendere questa convenzione uno standard per questo ambiente.
Una coppia di apici singoli ''' (l'apostrofo) viene utilizzata per delimitare una stringa che non dovrà essere oggetto di ulteriore interpretazione da parte del Perl. Così, volendo assegnare alla variabile $nome il valore 'Pippo' potremo usare l'espressione '$nome = 'Pippo'''.
I doppi apici i"' (le virgolette) sono invece utilizzate per delimitare una stringa il cui valore dovrà essere ulteriormente sviluppato dall'interprete Perl. In gergo tecnico si dice che l'interprete effettuerà l'interpolazione del valore della stringa, ossia esploderà il valore di eventuali variabili o stringhe di controllo contenute all'interno della stringa stessa.
Consideriamo il seguente esempio:
# !/usr/local/bin/perl # somma.pl: esempio di interpolazione $a = 3; $b = 4; $c = $a+$b; print 'con apici: $a+$b=$c\n'; print "\ncon virgolette: $a+$b=$c\n"; |
Eseguendo il programma somma.pl otterremo il seguente output:
$ somma.pl con apici: $a+$b=$c\n con virgolette: 3+4=7 $ |
Per rappresentare all'interno di una stringa delimitata da virgolette un carattere che in Perl ha un significato speciale, è necessario farlo precedere dal simbolo '\' (backslash) per evitare che l'interprete lo utilizzi attribuendogli il significato che ha nella sintassi del linguaggio. Ad esempio per visualizzare il simbolo '$' dovremo usare la sequenza '$', e lo stesso faremo per rappresentare simboli particolari come '"', '%', '@' ed altri ancora; il carattere '\' segue la medesima regola: per rappresentare il backslash sarà sufficiente ripeterne due di seguito ('\\').
L'apice inverso '`' (accento), presente sulle tastiere americane in alto a sinistra (codice ASCII 96), ha un significato completamente diverso rispetto agli apici ed alle virgolette. Serve infatti a racchiudere un comando che verrà eseguito aprendo un processo figlio dell'interprete Perl (tipicamente si tratta quindi di comandi della shell UNIX). L'output prodotto dal comando eseguito mediante l'apice inverso viene restituito all'interprete Perl (processo padre).
Ad esempio, sappiamo che il comando date della shell UNIX serve a visualizzare la data e l'ora corrente; volendo assegnare questo valore ad una variabile di un nostro script in Perl possiamo utilizzare la seguente espressione:
$data_odierna = `date +%d/%m/%y`; |
L'output del comando date viene catturato, senza che venga visualizzato sullo standard output, e restituito come valore di ritorno della chiamata del processo stesso.
Il Perl è un linguaggio in cui, come abbiamo visto, c'è una certa promisquità tra i tipi di dati: non è necessario stabilire se una determinata variabile conterrà dati di tipo numerico o stringhe; tuttavia è ben diverso eseguire una addizione tra numeri o una concatenazione di stringhe. A livello di operatori il Perl effettua quindi un cast delle variabili in base al tipo di operazione richiesta. In un certo senso si può dire che, trovandosi di fronte ad un operatore, l'interprete stabilisce il tipo di dato contenuto nelle variabili che compaiono nell'espressione da valutare, ``in base al contesto''.
Se verrà utilizzato un operatore aritmetico tra due variabili, il Perl tenterà di stabilire il valore numerico delle variabili stesse; viceversa se l'operatore sarà di tipo stringa allora il Perl tratterà le variabili coinvolte nell'espressione come delle stringhe.
Nelle tabelle 4, 5 e 6 sono riportati i principali operatori.
$a + $b | addizione | somma il valore di $a e quello di $b |
$a - $b | sottrazione | sottrae a $a il valore di $b |
$a * $b | prodotto | moltiplica $a e $b |
$a / $b | divisione | divide $a per $b |
$a % $b | modulo | restituisce il resto della divisione $a/$b |
$a ** $b | esponente | restituisce $a elevato a $b |
++$a, $a++ | incremento | aumenta di 1 il valore di $a |
--$a, $a-- | decremento | diminuisce di 1 il valore di $a |
$a . $b | concatenazione | restituisce una stringa che contiene $a seguito da $b |
$a x $b | ripetizione | restituisce una stringa che riporta il valore di $a ripetuto $b volte |
substr($a,$n,$l) | sottostringa | restituisce una sottostringa di $a, a partire dal carattere $n e lunga $l caratteri |
index($a,$b) | indice | restituisce la posizione del primo carattere della sottostringa $b all'interno di $a |
$a = $b | assegnazione | assegna a $a il valore di $b |
$a += $b | aggiungi a | aggiunge al valore di $a il valore di $b (equivalente a $a = $a+$b) |
$a -= $b | sottrai a | sottrae al valore di $a il valore di $b (equivalente a $a = $a-$b) |
$a .= $b | concatena a | concatena alla stringa $a la stringa $b (equivalente a $a = $a.$b) |