You are on page 1of 70

Sabin Corneliu Buraga

Introducere în
Programare Perl

2005

În loc de prefaţă…

Acest material realizează o prezentare generală a limbajului de programare Perl, insis-
tând asupra realizării de script-uri Perl în contextul programării Web pe partea de server
via paradigma CGI (Common Gateway Interface). De asemenea, se prezintă o serie de exem-
ple de programe Perl şi diverse propuneri de proiecte pentru a fi implementate de cititor.

Lucrarea de faţă se bazează, în cea mai mare măsură, pe cartea S. Buraga et al., Progra-
mare Web în bash şi Perl (include şi un CD), Editura Polirom, Iaşi, 2002:
http://www.infoiasi.ro/~cgi/.

Pentru aprofundarea limbajului Perl, cititorul este încurajat să consulte resursele bibli-
ografice. Mai mult, poate vizita situl autorului: http://www.infoiasi.ro/~busaco/. Aş-
teptăm reacţii şi opinii la adresa e-mail busaco@infoiasi.ro.

2

1. Prezentare generală a limbajului Perl

Pentru început, vom enumera câteva dintre caracteristicile specifice limbajului Perl.

1.1 Generalităţi

Creat iniţial pentru prelucrarea sofisticată a informaţiilor textuale, Perl (Practical Ex-
traction and Report Language) îl are ca părinte pe Larry Wall, în decursul timpului la
dezvoltarea limbajului contribuind şi alţi numeroşi programatori. Distribuit gratuit, Perl a
devenit favoritul administratorilor de sistem şi al programatorilor de aplicaţii Web, însă
poate fi utilizat asemeni altui limbaj general. Ca şi Linux, Perl a crescut în mediul prielnic
al Internetului, varianta curentă a limbajului fiind 5. Pe data de 18 decembrie 2005 se îm-
plinesc 18 ani de la apariţia limbajului. În curs de dezvoltare este versiunea Perl 6 a limba-
jului.

Iniţial, limbajul a fost conceput special pentru mediile UNIX, împrumutând o serie de
facilităţi oferite de shell-urile şi utilitarele standard şi păstrând filosofia de bază a UNIX-
ului, dar în prezent Perl este disponibil pentru toate platformele actuale (e.g. Mac OS,
Windows sau OS/2).

În proiectarea limbajului s-au avut în vedere următoarele principii:

• lucrurile simple să se poată realiza uşor, iar cele complexe să nu fie impo-
sibil de implementat;

• există mai multe modalităţi de realizare a unui program, în funcţie de gra-
dul de cunoaştere a limbajului de către dezvoltatorul acelui program.

Drept caracteristici importante ale limbajului se pot enumera:

• modularitatea

Perl oferă suport pentru mai multe paradigme de programare, ca de exemplu cea
procedurală şi cea orientată-obiect; limbajul poate fi extins prin intermediul aşa-
numitelor module, punându-se la dispoziţie un număr impresionant de module
standard;

• portabilitatea

Programele Perl se pot executa fără modificări pe orice platformă;

3

Programare Web în bash şi Perl. prin intermediul locaţi- ilor CPAN (Comprehensive Perl Archive Network)./configure # pentru configurare automata (infoiasi)$ .ro/~cgi/. procese. Buraga et al. Principala sursă este ftp://ftp. perldoc -f connect).2 Disponibilitate şi documentaţii Mediul Perl se poate obţine de pe Internet. pentru un mediu UNIX (Linux) va trebui să scriem următoarele linii de comenzi de la prompt-ul sistemului.perl. Pentru Windows. Perl nu oferă un interpretor clasic. Pentru anumite detalii sau documentaţii referitoare la modulele Perl. Perl poate fi folo- sit în special pentru dezvoltarea rapidă de aplicaţii de administrare a sistemului de operare şi destinate Web-ului. putem recurge la opţiunea -f pentru a afla detalii despre o funcţie (e. Astfel. 1. Polirom. 2002: http://www. dispo- zitive. Pentru a genera codul executabil al interpretorului Perl din sursele preluate din Inter- net.com/CPAN/. listate la http://www.. Fiind gratuit şi posedând numeroase mijloace de documentare online. de asemenea.fi. dacă dorim să aflăm amănunte despre funcţia standard Perl printf vom da perldoc printf.infoiasi. prin in- termediul expresiilor regulate şi a tablourilor. reprezentând un mediu ideal pentru conceperea script-urilor CGI. via FTP sau HTTP./Configure # pentru configurare manuala (infoiasi)$ make (infoiasi)$ make test (infoiasi)$ make install Perl include o serie de documentaţii online care pot fi parcurse prin intermediul bine- cunoscutei comenzi man (încercaţi. ca utilizatori cu drepturi de root: (infoiasi)$ . disponi- bilă şi pe CD-ul volumului S. man perl).g. ci un compilator-interpretor. anumite servere Web (e.. Mai mult. De asemenea. dar se pot folosi şi alte locaţii. orice distribuţie actuală de Linux include interpretorul şi manualele standard Perl. de exemplu. platforma Perl cea mai populară este ActivePerl. • expresivitatea şi puterea Limbajul dispune de mecanisme puternice pentru manipularea datelor.g. Perl poate fi folosit ca limbaj de sistem pentru lucrul cu entităţi ale sistemului de operare (fişiere.funet. • viteza de dezvoltare a aplicaţiilor Ciclul compilare-execuţie-depanare se poate realiza şi itera rapid. Apache) includ interpretoare Perl interne. De asemenea. 4 . Iaşi. se poate folosi comanda perldoc. socket-uri).

Tcl/Tk ori JavaScript.expresii regulate. Perl este un limbaj interpretat. perldsc . aplicaţie de birou). iar pentru a o converti în alte formate se pot folosi comenzile pod2man. De asemenea. • perlfaq . spre a fi rulat independent de interpretorul Perl).subrutinele Perl).com/perl/. navigator Web.perl sau documentaţiile în format hipertext de la http://www. Versiunile mai vechi de Perl puneau la dispoziţie documentaţia în format text (Plain Old Documentation . cititorii interesaţi pot parcurge articolele postate pe grupurile de ştiri comp. de o componentă numită motor (engine) Perl.structurile de date Perl (vezi şi perlre . Alte limbaje de tip script sunt bash. perlstyle . • perlop . • perldata . perlfunc .g..operatorii şi precedenţa lor. în sensul că instrucţiunile Perl nu sunt convertite în cod executabil (nu se generează un fişier executabil.introducere în structuri de date. Perl nu pune la dispoziţie un interpretor clasic. • perlobj - suport pentru programarea obiectuală (vezi şi perltool .răspunsuri la întrebările puse frecvent despre Perl (Frequently Asked Questions . Python. • perlmod .re- ferinţe. pod2html sau pod2text. rezultând un limbaj intermediar.3 Trecere în revistă a limbajului Spre deosebire de alte limbaje. • perlsyn . Pentru a avea acces la una dintre documentaţiile dorite.exemple de obiecte). perlref .modulele Perl (vezi şi perlmodlib). perldebug .ghid de stil. perlsub . server Web. ci în prealabil va fi compilat complet. un limbaj de tip script fiind destinat să prelucreze. Paginile de manual cele mai importante sunt: • perl .perl. sintaxa limbajului (vezi şi perlrun . perlbot . de exemplu. 1. în sensul că un script Perl nu este inter- pretat linie cu linie. perllol . să automatizeze şi să integreze facilităţile oferite de un anumit sistem (e.o trecere în revistă a documentaţiilor Perl.lang.liste de liste. Pentru amănunte. realizându-se diverse optimizări şi 5 . sistem de operare. este suficient să tastăm.FAQ). man perlsyn.execuţia script-urilor Perl.depanarea programelor. perlvar . tutorial privind programarea orientată-obiect.variabile predefinite).funcţii predefinite. consultaţi man pod. Vom spune despre programele Perl că sunt script-uri.POD).

Ne propunem să concepem un script care să contori- zeze numărul de apariţii ale elementelor dintr-un document XML: #!/usr/bin/perl # elemente_xml. 6 . prima linie a unui fişier sursă Perl va trebui să fie următoarea: #!/usr/bin/perl Această linie indică încărcătorului sistemului de operare locaţia interpretorului Perl (s- ar putea în unele cazuri să difere de directorul /usr/bin. fiind considerată simplu comentariu. va fi dat spre execuţie interpretorului Perl. # programul principal while (<>) { # cit timp se mai poate citi de la intrarea standard. %aparitii.. Ea va fi ignorată în alte medii diferite de UNIX (Linux). fişierul memorând script-ul Perl va trebui să aibă permisiunea de execuţie setată prin comanda chmod.raportându-se posibililele erori/avertismente sintactice sau semantice. daţi whereis perl pentru a vedea unde a fost instalat). Pentru a putea fi executat.. în cazul în care nu apar erori. vom scrie un program Perl din care vom putea remarca principalele ca- racteristici definitorii ale limbajului.pl # program care furnizeaza lista elementelor unice # prezente intr-un document XML si # numarul de aparitii ale fiecaruia my %elemente. Acest cod inter- mediar. Un prim program Perl În continuare. Modalitatea de execuţie a unui script Perl Având în vedere că Perl este un interpretor (similar shell-ului bash).

if (/<[^\/>]*>/) { # am intilnit "<". while ($restul_liniei =~ /<[^\/>]*>/) { $restul_liniei = $'.%2d aparitii. # subrutina de afisare a elementelor gasite # se vor sorta cheile tabloului asociativ %elemente # si se va afisa la iesirea standard fiecare cheie sub afiseaza_elemente { # pentru fiecare element al tabloului. # trecem la urmatoarea iteratie # daca elementul e instructiune de procesare 7 .. $element = $&. # gata! exit.. $aparitii{$element}. # atita timp cit in linia transmisa mai sunt # alte elemente XML. orice alte caractere # exceptind "/>" urmate de ">" # apelam o rutina de extragere a unui element &extragere_element. # orice caracter majuscul e transformat in minuscul $element =~ tr/A-Z/a-z/. "'$elemente{$element}'". foreach $element (sort keys %elemente) { # afisam formatate numele de element si # numarul aparitiilor lui printf "%-20s . } } # subrutina de extragere a numelor de elemente # apelata de fiecare data cind un element este detectat # intr-o linie citita de la intrarea standard # aceste nume vor fi stocate intr-un tablou asociativ # pentru extragerea numelor de elemente se va folosi # o expresie regulata =~ si variabilele $' si $& sub extragere_element { $restul_liniei = $_. } } # am terminat de prelucrat # vom afisa lista elementelor gasite &afiseaza_elemente().\n". # orice "<" sau ">" este eliminat $element =~ s/(<|>)//g...

caracterul EOF . } else { $aparitii{$element}++. $aparitii{$element} = 1. Vom salva codul sub denumirea elemente_xml. next if /^(<\?)/. vi.pl şi vom seta permisiunile de execuţie după cum urmează: (infoiasi)$ chmod 755 elemente_xml.pl Pentru a invoca interpretorul Perl vom folosi una dintre următoarele forme: (infoiasi)$ perl elemente_xml.0" ?> <studenti> <student> <nume>Gabriel Enea</nume> <an>4</an> </student> <student> <nume>Silvana Solomon</nume> <an>4</an> </student> <student> <nume>Manuel Subredu</nume> <an>3</an> </student> </studenti> ^D 8 . # altfel incrementam numarul de aparitii if ($elemente{$element} eq "") { $elemente{$element} = $element.pl sau: (infoiasi)$ . } } # final de "while" } # final de subrutina Programul anterior se poate edita folosind orice editor de texte (e./element_xml <?xml version="1. # il introducem in tablou.g.End Of File în Linux): (infoiasi)$ . vom semnala terminarea introducerii lor prin CTRL+D./elemente_xml Un exemplu de execuţie a acestui script este următorul (datele vor fi citite de la intrarea standard. daca nu exista. joe sau emacs).

'nume' . 'student' .006 De asemenea. 3 aparitii. recur- gând la afişarea valorii variabilei predefinite $]: (infoiasi)$ perl -e 'print "$]\n". Aceste opţiuni pot fi transmise interpretorului şi în cadrul liniei de preambul al codului. pentru mai multe detalii cititorul fiind îndemnat să consulte man perl. Rezultatul afişat la ieşirea standard va fi: 'an' . pot fi date şi alte opţiuni. de exemplu: #!/usr/bin/perl -w -t O opţiune utilă este "-e" care ne permite să executăm linii de cod Perl direct din linia de comenzi: (infoiasi)$ perl -e 'print "Salut!"' Astfel. Desi- gur. 3 aparitii. această opţiune va fi utilizată din raţiuni de verificare a corectitudinii programului. 1 aparitii.0 built for i386-linux 9 . putem folosi această opţiune pentru a afla versiunea curentă a limbajului. 'studenti' . De multe ori.' 5.6. utilizând opţiunea -v putem afla versiunea curentă a distribuţiei Perl in- stalate în sistem: (infoiasi)$ perl -v This is perl. Interpretorul Perl poate fi rulat cu diverse opţiuni. 3 aparitii. de exemplu opţiunea -w care va afi- şa toate avertismentele în timpul compilării şi rulării codului intermediar. v5.

delimitatorii fiind spa- ţiile albe.Caracteristici principale Putem observa că programul de mai sus este foarte asemănător cu un program scris în limbajul C sau cu un script bash. putem fo- losi aşa-numitele caractere escape. permanentă sau temporară pe parcursul execuţiei unui program. iar parantezele acolade sunt delimitatori de bloc de instrucţiuni. Tipurile de date în Perl sunt fie scalare (simple) sau compuse (complexe). • tipuri de date şi variabile . Fiind un limbaj interpretat. iar un şir de caractere cu valoarea "" (şir vid). $pi = 3. Perl nu impune declararea variabilelor. Perl este case sensitive. Această zonă poate fi publică sau privată.prima linie a programului declară două tablouri asociative care vor stoca elementele găsite şi respectiv numărul de apariţii ale acestora: my %elemente. Fiecare instrucţiune a limbajului este terminată de ". Reamintim faptul că o variabilă reprezintă o zonă (de obicei.".14152965. contiguă) de me- morie în care se stochează o valoare de un anumit tip. ele fiind automat ini- ţializate. 10 . Implicit. ca de exemplu "\n" (linie nouă) sau "\t" (carac- terul tab). %aparitii. se consideră că o variabilă nu- merică este iniţializată cu 0. vom prefixa nu- mele ei cu caracterul "$" după cum se poate remarca din exemplul de mai jos: $nr_studenti++.limbajul Perl are o sintaxă inspirată din C. Ca şi în C. Numele unei va- riabile trebuie să înceapă cu o literă şi poate conţine caracterele alfa-numerice şi "_". După cum era de aşteptat. În cele ce urmează vom încerca să descriem caracteristicile principale ale limbajului: • sintaxa . Ca tipuri scalare se pot aminti întregii cu semn şi numerele flotante (dublă preci- zie). Pentru a avea acces la valoarea unei variabile scalare. în funcţie de contextul utilizării. zonei fiindu-i asociat un nume (identificator al acelei variabile). Şirurile de caractere sunt delimitate de apostrofuri sau de ghilimele. Tot drept tip scalar se consideră tipul desemnând şiruri de caractere. $limbaj = "Perl". Recoman- dăm indentarea construcţiilor sintactice Perl şi utilizarea cât mai multor comenta- rii pentru ca programele să poată fi uşor de parcurs şi de înţeles de către cititor. iar comentariile sunt precedate de caracterul "#".

şirurile pot fi delimitate de con- strucţii precum: q/Victor Tarhon-Onu/ # identic cu 'Victor Tarhon-Onu' qq/Victor Tarhon-Onu/ # identic cu "Victor Tarhon-Onu" # executia unei comenzi. În loc de a folosi ghilimele sau apostrofuri. elementele unei liste fiind accesibile prin intermediul unui indice numeric. "Perl"). $pi). putem avea acces la un sub-tablou indicând un interval de indici (sub-tabloul fiind tot un tablou va avea numele prefixat de "@"): print "Primele trei limbaje: @limbaje[0. 11 . 1978. vom utiliza unshift() şi shift(). Dacă dorim să adăugăm şi să ştergem elemente la şi de la începutul unui tablou. diferenţa dintre apostrofuri şi ghilimele ca delimitatori de şir este dată de faptul că valoarea variabilelor este accesibilă în cazul ghilimelelor: print "Studenti: $nr_studenti\n". numele unui vector va fi precedat de caracterul "@". "Java". # variabila $limbaj nu va fi expandata print 'Acest $limbaj este greu?'. Drept tipuri complexe avem la dispoziţie: • tablourile indexate sunt liste ordonate de scalari. @mix = ("Pink". un tablou poate conţine elemente etero- gene. identic cu `ls -la` qx/ls -la/ qw/Perl C Java/ # lista de cuvinte Ca şi la shell-ul bash. "C". respectiv: push(@limbaje. @limbaje = ("Ada".2]\n". După cum se poate remarca. de tipuri scalare diferite. "Prolog"). Accesarea unui element se va realiza astfel (caracte- rul "@" este înlocuit cu "$" pentru că selectăm un element scalar): $limbaje[4] De asemenea. vom putea uzita de funcţiile predefinite push() şi pop(). "Lisp". respectiv. print "Ultimul limbaj eliminat:". Pentru a adăuga şi elemente la sfârşitul unui tablou. iar indicele va porni de la zero şi va fi în- cadrat între paranteze pătrate: @absenti[$nr_studenti] = 20. Elementele delimitate de "(" şi ")" compun o listă.. pop(@limbaje). "Floyd".

Tablourile pot fi utilizate nu doar în partea dreaptă a unei atribuiri. Pentru prima linie. variabila $prima va primi valoarea primului element al tabloului @limbaje. În a doua linie. @restul) = @limbaje. valoa- re). 25. vom utiliza o construcţie de genul: $sir = "@limbaje". Aceasta are acelaşi efect ca atribuirile individuale: $studenti = $absenti. "\n". $al_doilea) = @limbaje. cheile sau valorile nefiind ordonate. • tablourile asociative (hash) sunt tablouri în care indicele numeric este substituit de un şir de caractere. elementele tabloului vor fi delimitate de un spaţiu. 12 . "grupa2". Tablourile asociative vor fi acce- sate precedând numele lor cu caracterul "%". $sir = "@limbaje". Implicit. Folosind o construcţie similară putem realiza atribuiri multiple de vari- abile scalare într-o singură linie de program: ($studenti. 7). $profesori = 7. Pentru a schimba delimitatorul. ci şi în partea stângă: ($primul. $profesori) = ($absenti. $nr_limbaje = scalar(@limbaje). dar @restul va fi un tablou conţinând res- tul elementul tabloului @limbaje. Le putem vedea ca perechi (cheie. ($primul. print $sir. Pentru ca elementele unui tablou să devină cuvinte ale unui şir de ca- ractere. iar $al_doilea valoarea celui de-al doilea element al aceluiaşi tablou. putându-le iniţializa astfel: # numarul de studenti din fiecare grupa %grupe = ("grupa1". 20. $prima va primi de asemenea valoarea primului element al tabloului. Lungimea unui tablou va putea fi aflată astfel (cele trei construcţii au acelaşi efect): $nr_limbaje = @limbaje. vom apela la variabila scalară predefinită cu nume- le "@"" după cum se observă în următorul exemplu: $" = "|".

"grupa2" => 20. "grupa3". Această funcţie permite precizarea unei funcţii de comparaţie a elementelor definită de utilizator. dar valorile cheilor pot fi duplicate. Inversarea unei liste de elemente se va realiza cu reverse(). "grupa3" => 24. Un element se poate elimina cu ajutorul funcţiei delete(). O modalitate mai intuitivă este: %grupe = ("grupa1" => 25. nu valori ale cheilor. "grupa4" => 25). } Pentru sortarea unui tablou.\n". iar existen- ţa unui element se poate afla prin exists(): if exists($grupe{"grupa4"}) { delete($grupe{"grupe4"}).\n". Conversia din tabel indexat în tabel asociativ şi invers se poate realiza tot prin intermediul atribuirii obişnuite. iar cheile nu pot fi accesate specificând valorile lor între acolade. } Inserarea se poate face simplu prin: $grupe{"grupa5"} = 20. 25). vom putea scrie: print "Grupa a 3-a are $grupe{"grupa3"} studenti. 13 . Aceste liste pot fi iterate cu ajutorul instrucţiunii foreach. Funcţia standard each() returnează o pereche cheie-valoare putând fi fo- losită de asemenea la parcurgerea unui tablou asociativ: while (($grupa. Între acolade vor putea fi precizate numai nume de chei. vom apela funcţia sort(). 24. pop(). shift() sau unshift(). Pentru a accesa un anumit element. $studenti) = each(%grupe)) { print "Grupa $grupa are $studenti studenti. "grupa4". Asupra unui tablou asociativ nu mai putea aplica funcţiile push(). dar putem folosi funcţiile keys() şi values() pentru a obţine lista cheilor şi respectiv cea a valorilor unui ta- blou asociativ. O cheie trebuie să fie unică.

$studenti şi @studenti fără am- biguităţi.006).separatorul utilizat la afişarea listelor. putem folosi în acelaşi program nu- me de variabile precum %studenti. • Sunt puse la dispoziţie diverse variabile predefinite. Pentru a evita conflictul cu nume de variabile sau de funcţii predefinite (care întotdeauna sunt scrise cu minuscule). .separatorul de ieşire folosit de print() pentru afişa- rea câmpurilor de date. Se pot menţiona.numele programului care se execută. 'httpd.mesajul de eroare semnalat de interpretorul Perl re- turnat în urma execuţiei celei mai recente funcţii eval(). variabilele: • $$ .versiunea interpretorului Perl. vom putea alege identificatori de variabile scrişi cu majuscule: # se evita conflictul cu numele de functie log() open(LOG. • @INC . de exemplu.separatorul de ieşire pentru afişarea înregistrărilor. • %ENV .variabilele de mediu disponibile. • $" .g. sunt disponibile următoarele tablouri: • @ARGV . • $? . • $_ . utilizate la includere.identificatorul procesului curent. 14 . De asemenea. 5. nu numele programului).log').codul de eroare returnat de ultima comandă executa- tă. • $] .intrarea implicită sau spaţiul de căutare într-un şir (poate fi folosită şi $ARG). utile în anumi- te contexte. • $. • $0 .Remarci • Din moment ce numele de variabile sunt prefixate de caractere di- ferite în funcţie de tipul variabilelor.lista locaţiilor bibliotecilor standard Perl. • $\ .argumentele furnizate scriptului ($ARGV[0] referă primul argument. ca număr zecimal (e. • $@ .

mai pot fi utilizate referinţele la sub- rutine (funcţii sau proceduri). subrutine). un typeglob returnea- ză o valoare scalară care reprezintă toate obiectele Perl purtând numele respectiv (e. în interiorul unei subrutine sau în cadrul unui eval(). tablouri. se poate folosi construcţia "*" pentru a defini un typeglob. Această construcţie este similară celei oferite de limbajul C prin inter- mediul operatorului & (address-of). • Desigur. liste de liste etc. scalari. orice variabilă folosită undeva într-un program va fi accesibilă (vizibilă) oriunde în cadrul acelui program. subrutine sau eval(). descriptori de fişier. O variabilă local va salva valoarea variabilei globale cu acelaşi nume şi o va restaura la părăsirea blocului.g. Putem crea o referinţă la orice variabila sau subrutină Perl. $referinta_la_rutina = \&sortare. • local este similară cu my. iar atunci când este evaluat. generând structuri de date deosebit de complexe (tablouri aso- ciative conţinând ca elemente alte tablouri indexate sau asociative. • În afara tipurilor prezentate. Pot fi declarate cu my doar variabile scalare sau tablouri (indexate ori asociative). putem combina valorile scalare cu tablourile indexate sau asociative. putem preciza scopul (sau domeniul vizibilităţii ei). Dereferenţierea se realizează cu ajutorul operatorului $. 15 . Un typeglob (tip global) poate fi privit la un substitut al tuturor variabilelor care poartă acelaşi nume. se poate consulta man perllol. De asemenea. print "Inainte: $numar\n". prefixate de caracterul "&" sau la alte obiec- te. Pentru a limita vizibilitatea unei variabile. prin prefixa- rea acelui identificator cu caracterul "\": $referinta_la_mediu = \%ENV. vom folosi una dintre următoarele declaraţii: • my declară o variabilă ca fiind disponibilă doar în cadrul blocului de instrucţiuni curent. subrutinei sau construcţiei eval() în care a fost de- clarată. În mod normal. Pentru o variabilă. Pentru amănunte. Un exemplu de utilizare a declaraţiei local: $numar = 5.). cu excepţia faptului că variabila va fi disponibilă dinamic în cadrul unui bloc.

următoarele construcţii sunt echivalente: $sir !~ /sablon/ not $sir =~ /sablon/ • x este operatorul de multiplicare a unui şir sau tablou: # un rind de 80 de caractere "?" @rind = ('?') x 80. $numar++) { print "Numarul este $numar\n". 2 la puterea 5 va fi scris 2**5. Specifici limbajului Perl sunt următorii operatori: • ** este operatorul de exponenţiere (similar celui din Fortran). # un tablou hash initializat @studenti = qw(Silvana Daniel Gabriel). ast- fel. } } print "Dupa: $numar\n". este operatorul de concatenare a şirurilor de caractere (poate fi regăsit şi la PHP): $salut = "Buna " . @note{@studenti} = (10) x @studenti. Cuvântul cheie undef poate fi utilizat pentru a declara ca nedefinite diferite vari- abile: undef $absente. "ziua!" . undef &calcul_perimetru. stocând valoarea specială undef. $numar <= 6. precedenţa lor este ace- eaşi). • !~ este similar precedentului operator. • operatorii sunt cei similari din limbajul C (la fel. astfel. O variabilă scalară care nu conţine nici o valoare validă (număr sau şir de caractere) va fi considerată nedefinită. dar valoarea returnată este negată logic. 16 . for ($numar = 2. • \ este operatorul unar de creare a unei referinţe.{ local $numar. "\n". • =~ este operatorul de ataşare a unei expresii scalare la un şablon (pattern) al unei expresii regulate. • . Pentru a testa dacă o variabilă este definită vom putea utiliza funcţia predefinită defined().

33). putând fi utilizat în contextul listelor de numere sau şirurilor de caractere: # afisarea valorilor de la 1 la 33 print (1. • .. 0 dacă operanzii sunt egali şi +1 dacă operandul stâng este mai mare ca operandul drept. == şi != (ca în C). gt. le... eq şi ne (ca în Fortran). Aceşti operatori vor returna 1 pen- tru valoarea logică "adevărat" şi "" (şirul vid) pentru valoarea logică "fals". în loc de <=> vom folosi cmp. Pentru şiruri de caractere. Pentru compararea valorilor numerice se vor utiliza operatorii relaţionali <. # ultimele 3 limbaje print @limbaje[-3.'zz'). 17 . >=. # toate combinatiile de la 'aa' la 'zz' @combinatii = ('aa'. ge. >. este operatorul de definire a unui interval.-1]. Pentru a compara şiruri de caractere se vor folosi ope- ratorii lt. <=. Se mai poate folosi <=> pentru valori numerice care va returna -1 dacă operandul stâng este mai mic decât cel drept..

Observaţii

• Operatorul de autoincrementare oferă o funcţionalitate suplimen-
tară putând incrementa şi un şir de caractere:
print ++($grupa = 'g1'); # afiseaza 'g2'

• Operatorul unar - poate fi utilizat, de asemenea, pentru şiruri,
producând acelaşi şir, dar prefixat de caracterul "-":
$unu = "unu";
$minus_unu = -"unu";

• În Perl, există o multitudine de operatori unari care la prima vede-
re par funcţii; astfel, sin, cos, log, int, rand, oct, hex, exists,
delete, glob, ref, my, return sau exit sunt de fapt operatori unari.
Astfel, putem să nu încadrăm argumentele între paranteze, cele două linii
fiind echivalente:
$valoare = hex "CB74";
$valoare = hex("CB74");

Utilizarea lui exists ca operator poate fi urmărită în continuare:
print "Grupa exista\n" if exists $grupe{"grupa3"};

• Operatorii pe biţi pot fi utilizaţi nu numai pentru întregi, ci şi pen-
tru celelalte tipuri scalare:
# vom obtine "020.44"
print "123.45" & "234.56"

• Operatorii logici || şi && (similari cu cei din C) nu vor returna 0
sau 1, ci ultima valoare evaluată. De asemenea, pot fi folosiţi, având ace-
eaşi semantică, operatorii or şi and (desigur, în loc de operatorul negaţie
logică ! poate fi utilizat not).
open(FISIER, "index.html") ||
die "Fisierul nu poate fi deschis\n";

• Perl pune la dispoziţie şi operatorii de asignare, astfel încât urmă-
toarele construcţii sunt echivalente (unde OP este un operator Perl):
$variabila OP= $valoare;
$variabila = $variabila OP $valoare;

18

• instrucţiunile limbajului în Perl sunt în fapt expresii evaluate pentru efectele
lor colaterale. O secvenţă de instrucţiuni formează un scop denumit bloc, în gene-
ral un bloc fiind delimitat de paranteze, fiecare instrucţiune a blocului
terminându-se cu ";". În afară de instrucţiuni, un program Perl mai poate cuprin-
de declaraţii care pot fi văzute drept instrucţiuni dar care sunt efective la momentul
compilării, nu la rulare. Explicit, trebuie declarate obligatoriu numai declaraţiile de
formate şi de subrutine (după cum vom vedea mai jos).

Ca şi în alte limbaje, instrucţiunile pot fi grupate în instrucţiunile de asignare, in-
strucţiunile de test şi instrucţiuni de control.

Pentru instrucţiunile de test sau cele iterative, trebuie să precizăm faptul că
pentru obţinerea valorilor logice întotdeauna se va evalua în cadrul unui context
scalar. Regulile sunt:

• Orice şir de caractere este evaluat la valoarea "fals" dacă este vid
("") sau conţine caracterul zero ("0");

• Orice număr este evaluat ca "fals" dacă are valoarea 0
(sau 0.0);

• Orice referinţă este adevărată;

• Orice valoare nedefinită se consideră a fi falsă.

Majoritatea instrucţiunilor sunt similare celor din limbajele C sau Java, cu pre-
cizarea faptului că atât if, cât şi for sau while necesită prezenţa obligatorie a
acoladelor. Astfel, următoarea linie este corectă în C, dar generează eroare în Perl:
if ($nr_studenti >= 30)
printf ("Prea multi studenti...\n");

În loc de elseif la o instrucţiune if imbricată se va scrie elsif.

O instrucţiune specifică limbajului Perl este unless (complementara lui if) fi-
ind echivalentă cu un if având condiţia de test negată:
unless ($nr_studenti < 30) {
print "Prea multi studenti...\n";
}

Mai natural, putem scrie instrucţiunile if şi unless în forma postfixată:
print "Prea multi studenti...\n" if ($nr_studenti >= 30);
$nr_studenti-- unless $nr_studenti;

La fel, instrucţiunea de ciclare while poate fi scrisă astfel:
$nr_studenti++ while $nr_studenti < 30;

19

Complementara lui while este until, putând fi folosită în conjuncţie
cu do:
do {
$linie = <STDIN>;
# prelucreaza linia...
} until $linie eq ".\n";

Alături de for, avem la dispoziţie foreach, utilizată mai ales la iterarea tablou-
rilor, după cum am văzut. Expresia din paranteză este întotdeauna evaluată ca lis-
tă, fiecare element al acesteia fiind atribuit pe rând variabilei de ciclu. Variabila de
ciclu este o referinţă a listei, nu o copie a acesteia. Astfel, modificând într-un ciclu
foreach variabila de ciclu vom asista la modificarea tabloului pe care îl iterează:

@note = (9, 9, 7, 10, 5, 8, 8);
foreach $nota ( @note ) {
print "$nota\n" unless $nota != 10;
$nota++;
}
print "@note\n";

Instrucţiunile while, for şi foreach pot include o instrucţiune continue (fo-
losită rareori) care va defini un bloc de instrucţiuni ce va fi executat de fiecare da-
tă când s-a terminat blocul precedat de cuvântul cheie while sau la comanda ex-
plicită de trecere la următoarea iteraţie.

De exemplu, codul:
for ($grupa = 1; $grupa < 5; $grupa++) {
print $grupe{$grupa};
}

este echivalent cu:
$i = 1;
while ($grupa < 5) {
print $grupe{$grupa};
}
continue {
$grupa++;
}

După cum se poate remarca, semantica lui continue în Perl diferă de cea a in-
strucţiunii continue a limbajului C.

Pentru a modifica fluxul firesc de iterare al unui ciclu, se pot folosi next şi
last. Comanda next (similară instrucţiunii continue din C ori Java) permite
saltul la sfârşitul blocului de instrucţiuni şi începerea următoarei iteraţii. Comanda

20

21 . putând fi apelată astfel: aleatoriu(7). # cu parametru ('&' e optional daca se dau parametrii) listeaza_limbaje(@limbaje). dacă există. Rutina aleatoriu va avea un singur argument de tip scalar. Declaraţia unei subrutine are sintaxa: sub nume ( parametri ) { bloc } Lista parametrilor poate lipsi. Mai poate fi utilizată şi redo care restartează o iteraţie. foreach $limbaj ( @_ ) { print "\t$limbaj\n". Uzual. $grupa++) { next if $grupa == 2. } • subrutinele sunt funcţii sau proceduri care pot fi definite de utilizator ori- unde în program. require ori use) sau se pot genera dinamic. } } Apelarea unei subrutine se poate realiza în mai multe moduri. recurgând la funcţia eval(). # apelarea prin referinta ('&' poate lipsi) &$listeaza_limbaje(@limbaje). De exemplu: # fara parametri &listeaza_limbaje. Caracterul "&" poate lipsi din faţa unei subrutine dacă aceasta a fost definită în prealabil (ori dacă a fost importată dintr-un alt modul). "din zbor". last (similară cu break din C) va termina complet ciclul asupra căruia se aplică. nu este executat). pot fi încărcate dintr-un alt fişier (via do. fără a se evalua din nou condiţia (blocul continue. la fel şi blocul de instrucţiuni: # definirea unui prototip sub aleatoriu (@). la momentul declarării unei subrutine se realizează şi definirea corpului ei: sub listeaza_limbaje { print "Limbaje:\n". Un exemplu (a doua grupă nu va fi afişată): for ($grupa = 1 . $grupa <=4 . print "Grupa: $grupa\n".

Modelul de pasare a parametrilor de intrare şi ieşire este simplu: toţi parametrii unei subrutine sunt transmişi prin intermediul unei liste de scalari. vom utiliza return @_). de- sigur. putem folosi indici (e. Pentru ca o rutină să returneze valori codului apelant. În Perl subru- tinele pot fi apelate recursiv. Parametrii pasaţi oricărei rutine Perl vor fi regăsiţi ca tablou în variabila specială $_. undef. pentru a avea acces indexat la parametri specifici.g. $timp). Fiecare subrutină poate include variabile private declarate cu my. $_[0] pentru primul argument sau $_[2] care îl desemnează pe cel de-al treilea). se ob- servă utilizarea funcţiei predefinite printf pentru a afişa formatat diverse date. Limbajul Perl pune la dispoziţia programatorilor o paletă largă de funcţii predefinite. O altă funcţie des folosită este print (această ultimă funcţie nu realizează şi formatarea fixă a datelor). vom folosi return (dacă trebuie transmis un tablou. Un anumit parametru poate fi testat dacă este definit cu ajutorul funcţiei defined(). 22 . Putem furniza parametri nedefiniţi cu ajutorul lui undef: select (undef. cu conversii auto- mate de tipuri (dacă este cazul). În cadrul programului prezentat la începutul acestui sub-capitol. Acest lucru asigură pasarea unui număr variabil de parametri. Orice operaţiune cu tablouri poate avea loc. Mai mult. iar eventualele valori multiple returnate sunt disponibile tot ca listă de scalari. undef. ca şi în alte limbaje. şi asupra acestei variabile.

un tablou @x. $nume. În variabila $nume vor fi stocate caracterele preluate de la in- trarea standard.\n". poate fi utilizat într-o atribuire a unui tablou. o subrutină x etc. De asemenea. print STDOUT "Salut. Uneori este de dorit ca acest ultim caracter să fie eliminat.Prelucrarea fişierelor şi directoarelor Manipularea fişierelor la nivelul sistemului se realizează uzual prin intermediul descripto- rilor de fişier. chop($nume). folosind STDIN. print STDOUT "Un nume. Pentru a realiza acest lucru vom apela funcţia predefinită chop(): $nume = <STDIN>. vom recur- ge la funcţionalitatea oferită de operatorul "<>". Pentru numele descriptorilor de fişiere limbajul Perl rezervă un spaţiu de nume sepa- rat: aşa cum putem avea o variabilă scalară $x. Aceşti descrip- tori de fişiere au aceeaşi semnificaţie ca stdin. STDOUT şi STDERR pot fi utilizaţi fără a-i deschide. Operatorul "<>" poate fi folosit pentru orice descriptor de fişier. respectiv 2 din bash.\n". STDOUT şi STDERR. inclusiv caracterul newline care marchează finalul introducerii şirului de la terminal. Descriptorii STDIN. va rugam: ". un tablou asociativ %x. pentru că ei sunt implicit deschişi. în acelaşi program putem avea şi descriptorul de fişier x. fără nici un pe- ricol de confuzie. fiecare element al tabloului reprezentând o linie a acelui fişier: @linii = <DESCRIPTOR> 23 . În acest exemplu remarcăm şi specificarea explicită a descriptorului STDOUT ca argu- ment al funcţiei print(). Perl pune la dispoziţie trei descriptori de fişier care sunt preluaţi de la procesul părinte al interpretorului de comenzi şi sunt asociaţi dispozi- tivelor de intrare/ieşire deja deschise de acesta: STDIN. stdout şi stderr din limbajul C sau de- scriptorii 0.. Un descriptor de fişier desemnează o conexiune de intrare/ieşire între pro- gramul Perl şi sistemul de operare. 1. O altă funcţie utilă este chomp() care va şterge toate caracterele newline de la sfârşitul parametrului primit şi va returna numărul de caractere eliminate. caz în care se va citi întreg conţinutul unui fişier. $nume = <STDIN>. Ca şi alte limbaje de programare. $nume. În conjuncţie cu o variabilă scalară va realiza citirea unei linii de fişier. Pentru citirea unui şir de caractere de la intrarea standard. print "Salut.

NUMEFIS nu semnifică neapărat numele unui fişier din sistemele de fişiere locale sau montate prin reţea. La fel. deschiderea unui fişier se realizează cu ajutorul subrutinei open() ca- re acceptă unul. MOD. Un exemplu de deschidere. Mod Descriere Echivalent C < Citire "r" +< Citire şi scriere "r+" > Trunchiere şi scriere "w" +> Trunchiere şi scriere. NUMEFIS reprezintă numele de fişier căruia i se asociază descriptorul DESCRIPTOR. iar după apelarea lui open $DESCRIPTOR va fi alocat şi un descriptor de fişier cu acelaşi nume. iar MOD specifică maniera în care va fi deschis fişierul. atunci operaţiile de intrare/ieşire se vor realiza prin intermediul variabilei speciale $_. NUMEFIS) DESCRIPTOR este descriptorul asociat numelui de fişier (numele fişierului poate avea mai multe semnificaţii. cu posibilitatea citirii "w+" >> Scriere. doi sau trei parametri: open (DESCRIPTOR) open (DESCRIPTOR. NUMEFIS) open (DESCRIPTOR. după cum vom vedea mai jos). Similar altor limbaje. O altă variabilă pe care o putem folosi este $. În primul caz variabila $DESCRIPTOR conţine numele fişierului. numerotarea pornind de la 1. citire şi închidere a unui fişier este următorul: # parcurgem /etc/passwd 24 . adăugare la sfârşit "a" Modurile în care pot fi deschise fişierele Închiderea unui fişier se realizează cu subrutina predefinită close() care primeşte ca unic argument descriptorul de fişier dorit a fi închis. Dacă nu se specifică nici o variabilă. funcţia print() poate avea ca prim argument un descriptor de fişier (vezi şi exemplele de mai jos). care va indica numărul curent al liniei dintr-un fişier.

$home. $shell).\n" 25 . print "$username are drepturi de root. $passwd. open(DESCRIPTOR. $OUTPUT). my ($username. $uid. $gecos. $home. "cat /etc/passwd|"). print OUTPUT "$username are drepturi de root.\n" if $uid == 0. my ($username. Apelurile echivalente ale funcţiei open() în acest caz ar putea fi: open (DESCRIPTOR. $shell). $gecos. $gecos. my $infile="/etc/passwd". "cat /etc/passwd"). open (DESCRIPTOR. open (OUTPUT. $uid. putem înlănţui execuţia unor procese prin intermediul mecanismului pipe pre- zent şi la bash. $gid. $home.\n" if $uid == 0. $gid. $home. $uid. $gid. my $NUMEFIS="/etc/passwd". $shell) = split(/:/). $gecos.\n" if $gid < 90. print "$username este un utilizator privilegiat. Următoarele apeluri sunt echivalente din punctul de vedere al rezultatului obţinut: open(DESCRIPTOR. $passwd. "|-". "<". caz în care NUMEFIS poate fi un şir de comenzi externe de la care se va prelua ieşirea standard sau care vor avea drept intrare datele de ieşire scrise în descriptorul DESCRIPTOR. Un exemplu în care datele scrise într-un descriptor sunt preluate de un şir de comenzi externe poate fi următorul (foarte asemănător de altfel cu precedentul): my ($INPUT. while (<INPUT>) { ($username. } close(DESCRIPTOR). "<". open (DESCRIPTOR. print OUTPUT "$username este un utilizator privilegiat. $uid. "<$NUMEFIS"). $NUMEFIS). "/etc/passwd") || die "Nu se poate deschide /etc/passwd: $!\n". $shell) = split(/:/). "sort -u") || die "Nu se poate lansa sort: $!\n". while (<DESCRIPTOR>) { ($username. Numele fişierului poate fi precedat sau urmat de caracterul "|". open(DESCRIPTOR. $NUMEFIS) || die "Nu se poate deschide $NUMEFIS: $!\n". "-|". open (INPUT. $passwd. Astfel. $gid. "</etc/passwd"). $passwd.my $DESCRIPTOR.

$gecos. ">&OLDOUT"). while (<INPUT>) { ($username. Se pot folosi. $gid. print "$username este un utilizator privilegiat. $shell) = split(/:/). 26 . } close(INPUT)."sort -u") || die "Nu pot lansa comanda sort: $!\n". funcţiile uzuale seek(). $OUTPUT). similare celor din limbajul C. $shell).\n" if $uid == 0. $uid. my $infile="/etc/passwd". $passwd. Funcţia rewinddir() poate fi suplinită printr-un apel al lui seekdir(). opendir(). tell() şi flock(). $home. open (STDOUT. în care vom afişa linie cu linie conţinutul unui fişier. $uid. telldir() au corespondenţi similari printre funcţiile pentru lucrul cu fişiere. open (OLDOUT. close(OUTPUT). Astfel. în acest caz citirea efectuându-se de la intrarea standard. my ($username. print "$username are drepturi de root. close(STDOUT). $passwd."/etc/passwd") || die "Nu pot deschide /etc/passwd: $!\n". } Operatorul "<>" poate fi utilizat şi fără a specifica un descriptor. de asemenea. este: while(<>) { print "$. closedir(). seekdir(). ">&STDOUT") || die "Nu pot duplica STDOUT: $!\n". : $_". fiecare linie fiind precedată de numărul ei. open(STDOUT. Acelaşi rezultat se poate obţine prin duplicarea descriptorului de fişier corespunzător ieşirii standard: my ($INPUT. open (INPUT. Un alt exemplu. $gecos."|-". } close(INPUT).\n" if $gid < 90. $home. if $gid < 90. "<". $gid. Pentru prelucrarea conţinutului directoarelor există un set de funcţii diferite de cele destinate operării cu fişiere.

html>. fie prin intermediul funcţiei predefinite glob() şi poartă numele de globbing. 27 . $dirname). lstat(). construcţii similare celor din bash.\n". în limbajul Perl se pot folosi.html"). opendir(DIR. Câteva exemple: print "Dati un nume de fisier: ". link(). Apelul lor în Perl este similar cu cel din limbajul C. ioctl(). $nume = <STDIN>. symlink() şi unlink(). my $file. chomp $nume. de asemenea. @pagini = glob("*. die "Avem nevoie de cel putin un argument!\n" unless (defined($dirname = $ARGV[0]) && $dirname ne "").html din directorul curent. După cum se observă. chdir(). am folosit meta-caracterul "*" pentru a genera o listă cu numele tuturor fişierelor . if ( -r $nume && -w $nume ) { print "$nume poate fi citit/scris.$dirname) || die "Nu putem deschide directorul $dirname: $!\n". chown(). while (defined($raspuns) && $raspuns=~/y|d/i) { rewinddir(DIR). my $raspuns = "y". } closedir(DIR). Alte funcţii predefinite pentru lucrul cu fişiere şi directoare sunt mkdir(). while ($file = readdir(DIR)) { print "$file\n". rename(). rmdir(). Exemplu de citire a conţinutului unui director (simulează comanda ls): my ($DIR. $raspuns = <STDIN>. @pagini = <*. fileno(). Pentru a testa existenţa sau tipul unui fişier. În Perl acest lucru se realizează fie cu ajutorul operatorului "<>". Permisiunile unui fişier pot fi setate folosind funcţia chmod care primeşte aceeaşi pa- rametri ca apelul de sistem similar din C. } print "Mai afisam inca odata acestui director?". } O altă facilitate oferită este cea a expandării conţinutului unui director folosind specifi- catori de fişier.

28 . • O funcţie înrudită este warn() care nu va opri execuţia programului. Codul de eroare poate fi capturat prin intermediul variabilei speciale $!. } Semnalarea erorilor şi avertismentelor Din cele de mai sus se poate remarca faptul că apelarea unor funcţii precum open() se realizează în conjuncţie cu operatorii or sau || pentru a verifica dacă survin erori şi a in- dica natura lor. Dacă mesajul nu este terminat de caracterul "\n". ci doar va afişa şirul primit ca argument. Un alt exemplu. considerându-l mesaj de avertisment: open(LOG. afişând mesajul specificat ca argument. • În cazul unei erori fatale putem apela die() care opreşte forţat execuţia programului.log") || warn "Eroare la deschidere: $!". în care ştergem toate fişierele stocate în directorul /tmp: foreach (</tmp/*>) { unlink || warn "Eroare la stergerea $_: $!\n". ">>httpd. atunci funcţia die() va afişa şi numărul liniei de program care a cauzat eroarea.

} 29 . O expresie regulată reprezintă un şablon (pattern) căruia.1. şi alte limbaje oferă suport direct pentru expresii regulate. "fals" în rest (putem aşadar să-l folosim în cadrul expresiilor logice). Se returnează valoarea logică "adevărat" în cazul în care căutarea se încheie cu succes. se vor folosi drept expresii regulate simple şiruri de caractere. Pentru a manipula expresii regulate. în primele exemple de utilizare pe care le vom da. iar specificarea altei variabile se realizează prin intermediul operatorului "=~".4 Expresii regulate Pentru a înţelege funcţionalitatea programului prezentat la începutul acestei secţiuni mai trebuie să ne referim la una dintre cele mai interesante facilităţi oferite de limbajul Perl: expresiile regulate (pentru fundamentele teoretice ale expresiilor regulate. Deoarece de cele mai multe ori nu există nici un pericol de confuzie. Pentru lucrul cu expresiile regulate. pe baza unor reguli precise. Variabila implicită în care se realizează diferite acţiuni implicând expresii regulate este $_. De notat faptul că. Bu- cureşti. există un număr larg de utilitare şi aplicaţii care încorporează ex- presiile regulate ca parte a funcţionalităţii interne a respectivelor programe: comenzile UNIX/Linux de procesare a liniilor (grep. limbajul Perl pune la dispoziţie mai mulţi operatori care. În fapt. # atita timp cit se introduce ceva de la tastatura while (<STDIN>) { print "Am gasit subsirul \"Victor\" in $_" if m/Victor/. ne vom sluji de o serie de operatori descrişi în continuare. Operatorul m// Acest operator se foloseşte pentru a căuta un şablon în cadrul unui text dat. Editura MatrixRom. Limbaje formale şi automate. caracterul "m" care precedă expresia este opţional. Jucan. În afară de Perl. oferă un set de opţiuni pentru căutare şi/sau substituţie în cadrul unui text. cititorul inte- resat poate parcurge cartea T. 1999). putem da ca exemple Python ori Tcl. pe lângă rolul de delimitare. i se poate asocia unui text. sed sau awk) sau chiar shell-urile din sistem.

evaluează şablonul doar o singură dată. Un exemplu: while (<STDIN>) { s/autmat/Automat/i.caută în şir toate secvenţele care se potrivesc şablonului: my $sir = "a b r a c a d a b r a". } În acest exemplu spaţiul dinaintea caracterului "#" care precede un comentariu va fi ignorat. Operatorul s/// Operatorul s/şablon/text/ permite căutarea şi substituţia unui şablon cu un text. 30 . while ($sir =~ /a/g) { $num_a++. print. } print "Am gasit de $num_a ori caracterul \'a\'.căutare case-insensitive (majusculele nu diferă de minuscule): while (<STDIN>) { print "Am gasit tag-ul \"<b>\" sau \"<B>\" in $_" if /<b>/i. my $num_a = 0. # va afisa "Am gasit de 5 ori caracterul 'a'.\n". Cea mai utilizate opţiuni ale acestui operator sunt: • i . dar nu şi spaţiul alb precedat de un caracter "\" dintre "x" şi "t"." • o . } • x . while (<STDIN>) { print if /$ARGV[0]/o. la fel ca şi spaţiul dintre "e" şi "x". Folosirea lui în căutări succesi- ve în acelaşi şablon are ca efect creşterea vitezei de căutare. } • g .permite utilizarea de spaţii albe şi comentarii în cadrul expresiei regula- te cu scopul de a face codul mai lizibil: while (<STDIN>) { print if /^e x\ tins # tipareste daca linia incepe # cu 'ex tins' /sx.

m#</pre>#i. Expresia regulată precompilată poate fi memorată într-o variabilă şi refolosită în construcţia altor expresii regulate sau poate fi utilizată direct: my $expr = qr/(autmat|automt)/i. print. Un alt exemplu. Putem prece- da cu backslash orice caracter având semnificaţie aparte pentru a nu mai fi special proce- sat. Expresia se mai putea scrie şi s#/abc#AbC# sau s|/abc|AbC| ori s@/abc@AbC@. # exemplu de folosire in alte constructii while (<STDIN>) { s/altceva\ $expr\ nimic/Altceva\ Automat\ ceva/. Operatorul qr// Acest operator primeşte ca parametru un şir de caractere pe care îl precompilează ca expresie regulată. # exemplu de folosire directa while (<STDIN>) { s/$expr/Automat/. care va afişa conţinutul tuturor elementelor <pre> dintr-un document HTML (caracterul "/" nu mai putea fi folosit ca delimitator de expresie regulată): while (<>) { print if m#<pre>#i . a şirului substituitor se poate realiza cu alte caractere speciale decât "/". dacă este cazul.. Delimitarea expresiei regulate şi. Astfel. De remarcat faptul că operatorii m//. } my $expr=qr/(autmat|automt)/i.} Va înlocui cuvântul autmat dat la intrarea standard cu Automat şi va scrie toate liniile citite la ieşirea standard indiferent dacă substituţia s-a efectuat sau nu. # inlocuim "/abc" cu "AbC" print "$text\n" if $text =~ s!/abc!AbC!. print. s/// vor folosi valoarea variabilei $_ pentru căutarea şablonului dacă nu este utilizat nici unul dintre operatorii =~ sau !~. } 31 . } Am utilizat construcţia escape "\ " pentru ca spaţiul să nu fie interpretat. secvenţa de cod de mai jos este perfect valabi- lă: my $text = "123 /abc XYZ".

De multe ori însă am dori să folosim diverse meta-caractere pentru a identifica un set de caractere. În cadrul unei expresii regulate meta-caracterele sunt folosite pentru alcătuirea unor construcţii cu rol de a identifica diferite secvenţe de caractere dintr-un text.]" reprezintă o clasă de caractere. 8. 6. 32 . • Desemnează începutul unei linii. comparaţia dintre şirul %0bX7-0F comparat cu expresia regulată de mai sus se va finaliza cu succes datorită subşirului bX7-0. exceptând caracterul newline "\n". Secvenţe pentru identificarea unui caracter. remarcăm şi utilizarea operatorului . De exemplu. semnul minus "-" şi oricare cifră diferită de 1. Scrierea unui caracter "a" într-o expresie regulată presupune existenţa aceluiaşi caracter în şirul căruia i se aplica. Bineînţeles. iar [^a-m] va identifica oricare caracter cu excepţia minusculelor de la "a" la "m". se pot concepe construcţii mai complexe. Următoarele caractere ASCII sunt considerate meta-caractere în cadrul unei expresii regulate: • Caracterul ".. cum ar fi /[a-z][ATX][0-7]\-[^1-378]/ care va identifica orice text conţinând o suc- cesiune de caractere formată. 2. 9. fiind un caracter de poziţionare în rest. 7 sau 8.. Multiplicatori Cel mai simplu mod de a identifica un anumit caracter în cadrul unui text este cel de a căuta exact acel caracter. una dintre majuscu- lele "A". • Meta-caracterul "^" are două roluri: • Folosit în cadrul unei secvenţe de caractere are rolul de negare. în ordine. • Construcţia "[. 7. Meta-caracterele sunt acele caractere din codul ASCII care nu se identifică pe ele însele în cadrul unei expresii regulate sau chiar al unei secvenţe de cod-sursă (scrisă în C/C++. ^[2-5] va identifica orice şir care începe cu o cifră cuprinsă între 2 şi 5. Precedat de un "\" va desemna caracterul "^"." este utilizat în cadrul unei expresii regulate să identifice orice caracter. 0}. o cifră între 0 şi 7. De exemplu. 3. de o literă minusculă. De exemplu expresia regulată /[a-z]/ se poate asocia oricărui şir de caractere care conţine cel puţin o literă minusculă.. Perl etc). În acest exemplu. [^2-5] va identifica oricare cifră aparţinând mulţimii {1. care se dovedeşte extrem de util aici pentru extragerea unui interval de linii fără a se reţine explicit aceste informaţii. Astfel. "T" sau "X".

33 . • Caracterul "|" va da posibilitatea de a alterna între două sau mai multe forme posibile ale unei secvenţe dintr-un text. print LOG "linia $i: s-a inversat \"$1\" cu \"$2\"\n". while (<STDIN>) { print if (/[0-9]|[A-Z][a-z]/). • Simbolul "$" folosit într-o expresie regulată identifică sfârşitul unei linii.log") || die "Nu pot deschide fisierul: $!\n". } Următorul script va putea identifica orice şir care conţine un subşir format sau dintr-o literă minusculă urmată de cel puţin o cifră. ">>/tmp/word_switch. Subşirul care se potriveşte şablonului va fi tipărit: while(<>) { print "\"$1\" se potriveste sablonului\n" if (/([a-z]\d+|\d[A-Z]+)/). } • Meta-caracterele "?". open(LOG. while (<STDIN>) { $i++.g. s/^(\S+)\s+(\S+)/$2 $1/. "^" sau "$") se numeşte atom al unei expresii regulate. } close(LOG). "*. "{" şi "}" au rolul de multiplicatori ai unui atom. $i). • Caracterele "(" şi ")" au rolul de a grupa atomi în cadrul expresiei regula- te şi de a memora valoarea subşirurilor din text corespunzătoare acestor atomi. print. Un caracter lipsit de semnificaţie sau un meta- caracter de poziţionare (e. Acest program va prelua linii de text de la intrarea standard şi va afişa la ieşirea standard inversând primele două cuvinte între ele. Fie script-ul: my ($LOG. scriind într-un fişier modifică- rile efectuate. Putem grupa atomi pentru a forma fragmente ale unei expresii regulate mai com- plexe. sau dintr-o cifră succedată de cel puţin o majusculă. "+. fără însă a modifica valoarea expresiei regulate (această construcţie se mai numeş- te şi operator de memorare).

dar nu mai mulţi de n. • atom{n} va identifica exact n atomi. {0. • atom{. n} va identifica într-o expresie cel puţin m atomi.n} va identifica n atomi cel mult. • Un atom urmat de "+" poate să identifice măcar o apariţie a ato- mului.} este echivalent cu "+". una sau mai multe apariţii con- secutive ale aceluiaşi atom. Dacă meta-caracterul "?" urmează unui multiplicator. acesta din urmă va avea un caracter ponderat (minimal). } Multiplicatorul "{}" are o sintaxă ceva mai complexă decât "*" şi "+".1} cu "?". Un exemplu: while (<STDIN>) { print "Cel putin o aparitie a cuvintului \'web\' la inceputul liniei\n" if (/^(web)+/).} este echivalentă cu "*". Valorile lui m şi n sunt în intervalul [0. astfel: • atom{m. 65535]. Limbajul Perl pune la dispoziţie un set de construcţii predefinite pentru identificarea unor clase de caractere. • Un atom al unei expresii regulate urmat de "?" poate identifica de zero sau maxim o singură dată un atom. 34 . Putem face aici observaţia că {1. iar construcţia {0. • atom{m. după cum se poate remarca din tabelul următor. • Simbolul "*" poate identifica zero.} va identifica m sau mai mulţi atomi.

deşi o posibilă variantă a valorii lui $1 ar fi fost 23ABCDEFG.*\d+[A-Z]{3. Astfel. condiţiile impuse fiind satis- făcute.". mai mult. şi. Construcţia /(\d+[A-Z]{3.7})/. valoarea stocată de $1 va fi 3ABCDEFG. Totuşi un şir de forma abc123ABCDEFGHIJKL se va potrivi acestei expresii regulate.7})/ poate identifica orice şir de caractere cu următoarea componenţă: începe cu oricare caracter(e). în variabila $1 (s-a folosit () . cel mai din stânga va identifica mai multe caractere în detrimentul celorlalţi aflaţi mai în dreapta. Forma textului pe care îl va identifica nu se schimbă.7} în prima variantă a exemplului prezentat după ce va găsi în text trei majuscule./ va forţa ca în componenţa şirului să nu existe mai mult de şapte majuscule. să fie urmate de caracterul ". de exemplu. Dacă însă la sfârşitul acestei expresii mai adăugăm o constrângere (final de linie. Folosind în continuare şi- rul abc123ABCDEFGHIJKL. dar nu mai mult de şapte. însă textul memorat în $1 diferă în situaţiile în care vor exista mai mult de două cifre.*(\d+[A- Z]{3. De ase- menea. va continua căutarea şi se va opri la şapte dacă este posibil. nici mai puţin de trei. sau alt caracter) multiplicatorul {} va fi forţat să se oprească. În cazul prezenţei în expresia regulată a doi (sau mai mulţi) multiplicatori. Toţi aceşti multiplicatori prezentaţi mai sus vor identifica atât de mulţi atomi cât este posibil.7})\. [A-Z]{3. Construcţie Echivalentul construcţiei Construcţie Echivalent complementară complementare \D \d [0-9] (orice [^0-9] (o cifră) exceptând cifre) \w \W (un caracter [0-9_a-zA-Z] [^0-9_a-zA-Z] (un caracter alfanumeric) ne-alfanumeric) \S \s [\t\r\n\ \f (orice exceptând [^\t\n\r\ \f] (un spaţiu alb) ] spaţii albe) Identificarea claselor de caractere Expresia regulată /(.operatorul de memorare) fiind stocat şirul 123ABCDEFG. \d+ a identificat toate cele trei cifre din text. 35 . continuă cu cel puţin o cifră şi se termină cu cel puţin trei majuscule. Considerăm o variantă puţin modificată a expresiei de mai sus şi anume /^.

graph. de forma [:clasa_de_caractere:]. [[:word:]] este echivalentă cu [0-9a-zA-Z_]. [[:digit:]] cu [0-9] etc. alnum. Să considerăm expresia regulată /(a. În acest caz compararea s-a făcut până la sfârşitul şirului de caractere. • \Z identifică sfârşitul unui şir sau înaintea caracterului newline de la finalul şirului. 36 . "text". alături de construcţiile predefinite pentru identifi- carea unor clase de caractere. upper. nu caractere. utilizate şi de funcţiile PHP. dar nu şi "textul". "context". space. dar nefi- ind îndeplinite condiţiile de identificare s-a revenit la ultima succesiune de caractere "po- trivită". [[:alnum:]] este echivalentă cu [0-9a-zA-Z]. O com- paraţie între acest şir şi /(a. şi construcţii conforme cu standardul POSIX. De asemenea. print. Există situaţii când un asemenea comportament al multiplicatorilor nu ne convine. Se observă că deşi compararea s-ar fi putut opri după prima pereche bc. Alţi identificatori de caractere Limbajul Perl mai pune la dispoziţie. a continuat. • \B identifică orice alt context decât limitele unui cuvânt (interiorul unui cuvânt). limbajul Perl defineşte construcţii cu lungime nulă (zero-width assertions) care identifică doar contexte. cntrl. Clasele de caractere (care pot fi utilizate ca mai sus) sunt: alpha. • \z identifică sfârşitul unui şir. • \G va identifica locul unde are loc ultima potrivire a şablonului în text. De exemplu "/text\b/" poate identifica " text". punct.*bc)/ va avea ca rezultat memorarea în $1 a valorii a ddd bc dddd bc. Astfel. lower. Caracterele incluse în aceste clase de caractere sunt cele pentru care funcţiile C cu numele is- clasa_de_caractere() returnează "adevărat". în următorul mod: • \b identifică limitele unui cuvânt. în cazul folosirii opţiunii /g a operatorilor m// sau s///.*bc)/ şi textul dd a ddd bc dddd bc bdd. ascii. word şi xdigit. • \A desemnează începutul unui şir. digit.

Un exemplu de folosire al lui qr// în acest caz este evaluarea unor părţi ale unei expresii regulate numai o singură dată.Utilizarea variabilelor în expresiile regulate Operatorii delimitatori care încadrează expresiile regulate au un comportament asemă- nător ghilimelelor (double quote). variabilele care intră în compo- nenţa unui şablon sunt evaluate la fiecare evaluare a acestuia în vederea căutării în text. print. $expresie = qr/$text_inlocuit/. artificiu care poate mări viteza de procesare a unor texte folosind expresii regulate complexe având părţi care rămân ne- schimbate mai mult timp: my ($text_de_inlocuit. $text_inlocuit. chomp($text_inlocuit = <>). print "Cu ce text vom inlocui \"$text_inlocuit\"? ". print "Ce text vom inlocui in text? ". ca şi în alte cazuri. } 37 . while (<>) { s/$expresie/$text_de_inlocuit/i. $expresie). Astfel. Foarte util în unele cazuri ale utilizării variabilelor în cadrul expresiei regulate se dove- deşte operatorul qr//. Excepţie fac expresiile regulate delimitate de ghilimele simple (single quotes) care inhibă evaluarea sau în cazul folosirii opţiunii /o care ne asigura de faptul că acea expresie regu- lată este compilată doar o singură dată. chomp($text_de_inlocuit = <>).

open (FIS.1.va realiza translatarea utilizând complementara mulţimii de ca- ractere de căutare. După cum vom vedea în secţiunea 2. Pentru a afişa numele de cont şi directorul home al utilizatorilor din sistem vom putea scrie următorul script (folosim fişierul /etc/passwd). Se pot folosi opţiunile: • c .va şterge toate caracterele din mulţimea caracterelor de căutare care nu au corespondent în setul caracterelor de înlocuire. înlocuindu-se fiecare apariţie a unui caracter de căutare cu corespondentul lui din mulţimea caracterelor de înlo- cuire. • d . Câteva exemple: # majusculele devin minuscule tr/A-Z/a-z/ # http: devine ftp: tr/http:/ftp:/ # caracterele diferite de alfanumerice devin spatii tr/A-Za-z0-9/ /cs • split() împarte un şir de caractere în funcţie de o expresie regulată şi returnează un tablou conţinând subşirurile care nu satisfac acea expresie regulată. "/etc/passwd") || die "Eroare la deschiderea fisierului\n". funcţia va fi foarte folositoare pentru rea- lizarea de script-uri CGI. Şirul de intrare este parcurs caracter cu caracter.va reduce secvenţele de caractere care au fost înlocuite folosindu-se acelaşi caracter la o apariţie unică a caracterului respectiv. chomp($linie). • s . while (<FIS>) { $linie = $_.Funcţii predefinite folosind expresii regulate În conjuncţie cu expresiile regulate se pot utiliza următoarele funcţii predefinite: • tr/// realizează translatarea caracter cu caracter a unui text şi are forma: tr/caractere_de_căutare/caractere_de_înlocuire/ Această funcţie mai poartă numele şi de funcţie de transliterare. 38 .

print "Directorul home al lui $cont este $dir\n". Putem considera expresia ca o subrutină sau bloc de instrucţiuni în care toate variabilele locale au timpul de viaţă egal cu cel al subrutinei ori blocului. print "Limbaje: ". 6]. Posibilele erori vor cauza returnarea unei valori nedefinite şi setarea variabilei $@ cu un mesaj de eroare. $data_sistem). • eval() poate fi folosită pentru evaluarea/execuţia unei expresii Perl. "\n". $tcl). Valoarea returnată de eval() reprezintă valoarea ultimei expresii evaluate. O variantă alternativă este cea care recurge la utilizarea operatorului de conca- tenare ". $cpp. $dir) = @date[0. $perl. Astfel. se va utiliza în mod firesc variabila specială $_. $num. $java. $tcl). în sensul că reuneşte mai multe şiruri de caractere în unul singur. Dacă nu se specifică o expresie ca argument al funcţiei. Contextul execuţiei expresiei Perl este contextul curent al programului. "\n". $linie). 1 } || 0. $java = "Java". ($ziua. } 39 . $tcl = "Tcl". $an) = split(/\s+/. pentru a stoca data sistem vom putea scrie următoarele linii de cod: $data_sistem = localtime(time). $cpp = "C++". $java. ($cont. } close (FIS). $cpp. return eval { "" =~ /$sablon/. fără posibilitatea de a specifica elementul de legătură. fiind permisă şi folosirea operatorului return. $luna.". $timp. print "Limbaje: ". @date = split(':'. Astfel. Un exemplu: $perl = "Perl". delimitate de un scalar. $perl. eval() poate fi de ajutor în verificarea corectitudinii unui şablon: sub este_sablonul_valid { my $sablon = shift. ". join(" ". join(". • join() este complementară funcţiei mai sus amintite. Elementele returnate de split() se pot memora şi în variabile scalare separa- te.

Putem preîntâmpina afişarea unui mesaj de eroare la apariţia excepţiei de îm- părţire la zero a unui număr astfel: print "Impartire la zero" unless eval { $rezultat = $nr1 / $nr2 }. 40 .

1. La fel. se consideră implicit pachetul main. pentru metode: $imagine = new GD::Image(174.5 Modulele Perl Conceptul de pachet Modulele (pachetele) Perl reprezintă unităţi de cod precompilat. Dacă nu este specificat numele pachetului. construcţia $::var este echivalentă cu $main::var. dintre care se pot menţiona: 41 . se ofe- ră suport pentru derivarea unei metode aparţinând unui pachet. Modulele Perl vor fi incluse în program. cititorul poate consulta paginile de manual pentru perlmod şi perlxs. Dacă dorim să accesăm metode sau date-membru definite într-un pachet derivat din altul vom specifica numele ambelor pachete: $Pachet::Subpachet::variabila Conceptul de modul Un modul reprezintă un pachet public definit într-un fişier . Un pachet Perl poate fi considerat drept implementarea unei clase pe care o putem in- stanţia în cadrul unui script. Subrutinele incluse într-un pachet pot juca. Sunt puse la dispoziţie mai multe module standard (disponibile în orice distribuţie Perl actuală). prin construcţia: use Modul. Mai mult.. Astfel. încapsulând diferite func- ţionalităţi oferite programatorilor. este echivalent cu require Modul. spre a fi folosite. Pentru mai multe detalii. La fel. 333). Vom referi variabilele din alte pachete prefixând identificatorul variabilei respective cu numele pachetului urmat de "::". de asemenea. Mai multe pachete pot fi grupate în biblioteci. astfel încât pachetele Perl pot fi ierarhizate. existând posibilitatea definirii de constructori şi destructori. dar se recomandă utiliza- rea lui use în favoarea unui require.pm cu scopul de a fi reutili- zat ulterior. rolul de metode. use Modul (). după cum se poate observa din următorul exemplu: $intrare = $main::STDIN.

colecţie referită sub denumirea CPAN (Comprehensive Perl Archive Network). modemuri). • CGI (pentru generarea facilă de script-uri CGI). • POSIX (pentru asigurarea interfeţei cu standardul POSIX IEEE 1003. • File::Handle (pentru manipularea fişierelor folosind descriptori de fişier). accesibilă prin inter- mediul comenzii man din UNIX. • interfeţe (la nivel scăzut sau ridicat) cu sistemul de operare. • Config (pentru acces la opţiunile de configurare). • Carp (pentru controlul erorilor şi avertismentelor). • Time::Local (pentru acces la timpul local). CPAN Succesul limbajului Perl rezidă. În afara modulelor din distribuţiile Perl standard. • Socket (pentru realizarea de operaţiuni cu socket-uri). • Search::Dict (pentru căutarea unei chei într-un fişier dicţionar). • ExtUtils::Embed (pentru includerea de cod Perl în programele C).. • suport pentru dezvoltare de programe/module. Se poate utiliza şi comanda perldoc. în principal. fiecare modul posedă propria lui documentaţie.pm" -print În mod normal. • File::Find (pentru traversarea recursivă a unui arbore de directoare). din posibilitatea de a extinde limbajul cu noi funcţionalităţi oferite de module. • File::Path (pentru operaţii cu directoare). • Env (pentru accesarea variabilelor de mediu). există o colecţie globală a tuturor materialelor publice referitoare la Perl.g. • Math::Complex (pentru prelucrarea numerelor complexe). 42 .1). Pentru a găsi toate modulele instalate în sistem (inclusiv cele care nu au documentaţii sau au fost instalate în afara distribuţiei standard) putem folosi următoarea linie de co- menzi: find `perl -e 'print "@INC"'` -name "*. CPAN oferă un număr impre- sionant de module grupate pe următoarele categorii: • extensii de limbaj şi unelte de documentare. în reţea şi controlul dispozitivelor (e. • comunicarea între procese.

perl.). fie ca fişier .pm (deja dezarhivat). • procesarea fişierelor de configuraţie şi a parametrilor în linia de comandă.tgz). Instalarea unui modul În unele cazuri va trebui să luăm un modul de la CPAN pentru a-l instala şi folosi ulte- rior în cadrul script-urilor noastre. consultaţi http://www. • procesarea fluxurilor de date şi a fişierelor. • altele. securitate şi criptare. Pentru un listing al tuturor locaţiilor Internet referitoare la CPAN. • procesarea informaţiilor grafice. • procesarea fişierelor şi sistemelor de fişiere. utilizatorul trebuie să aibă drepturi de root): 43 . • suport pentru arhivarea şi compresia datelor. un mo- dul Perl se regăseşte fie ca fişier tar arhivat cu gzip (deci are extensia . • interfeţe cu alte limbaje de programare. • procesarea caracterelor. • suport pentru poşta electronică şi grupurile de ştiri. • suport pentru Web (HTML. Orice modul Perl necesită pentru instalare existenţa interpretorului Perl în sistem. • autentificare. XML etc. HTTP. • controlul fluxului (excepţii. • interfeţe cu bazele de date. După dezarhivare (cu tar -xzf numearhiva. • tipuri de date şi conversii. în directorul în care a fost stocat modulul dorit a fi instalat se dau următoarele comenzi (pentru a se putea executa ultima linie. CGI. • interfeţe cu utilizatorul.com/perl/. erori etc. • suport pentru diverse limbi şi alfabete (internaţionalizare). Pentru a fi instalat pe un sistem UNIX/Linux.tgz).). • utilitare pentru daemoni.tar.gz sau .

\. fiecare modul este acompaniat şi de documentaţia necesară exploatării lui. Pentru a avea acces la ea.pm >Parser. respectiv.)|(\.PL make make test make install Dacă se doreşte instalarea unui modul într-o altă locaţie (de exemplu.html 1. if ($testmail =~ /(@. } else { return 1. se foloseşte utilitarul perldoc: (infoiasi)$ perldoc XML::Parser Pentru convertirea documentaţiei în format text sau HTML se pot utiliza comenzile pos2text şi.6 Exemple simple Vom furniza în continuare o serie de exemple de rutine Perl folositoare.]+\. return 0 if ($testmail =~/ /). ƒ Pentru a verifica validitatea unei adrese de e-mail putem recurge la funcţia urmă- toare: sub valid_email { $testmail = shift.)/ || $testmail !~ /^.)|(@\.4}|[0-9]{1. pod2html. În mod uzual.3})(\]?)$/) { return 0. în directorul pri- vat al unui utilizator). în care /home/user/director este directorul unde a fost instalat modulul denumit Modul.PL INSTALLDIRS=site INSTALLSITELIB=/home/user/director Pentru a folosi acel modul în programele noastre.pm >Parser. atunci se substituie prima linie cu: perl Makefile.([a-zA-Z]{2.txt (infoiasi)$ pod2html Parser. va trebui să prefaţăm fiecare script cu liniile de mai jos: use lib '/home/user/director' use Modul. } } 44 . ca în exemplul următor: (infoiasi)$ pod2text Parser.@)|(^\.+\@(\[?)[a-zA-Z0-9\-\.*@)|(\.perl Makefile.

'Aug'. } close (FIL).'Dec'). sprintf("%02d". my @WDAYS = ('Dum'. linie cu linie. sprintf("%02d". 'Apr'." . } ƒ Determinarea timpului curent şi preluarea lui într-un şir de caractere formatat co- respunzător (pentru Web) se pot realiza via funcţia de mai jos: sub get_time() { my @time = @_." . $wday) = @time. 'Iul'. sprintf ("%02d". 'Vin'.m').$day&nbsp. 'Sep'. } 45 . return ($ftime). "&nbsp. "&nbsp. ":" . $hour. 'Mar'. (1900 + $year) . $hour. $month. $min. while(<FIL>) { print. ":" . $MONTHS[$month] . 'Iun'. 'Joi'. 'Oct'. $min) . $day. 'S&icirc. "&nbsp. ƒ Afişarea. a conţinutului unui fişier se poate realiza astfel. "<$file"). $sec). local ($ftime) = $WDAYS[$wday] . return 1 unless open(FIL. $min. $hour) . 'Mar'. $month. 'Feb'. $day. prin inter- mediul subrutinei următoare: sub gen_file_content() { $file = shift. my ($sec. return 0. my $sec. 'Lun'." . my @MONTHS = ('Ian'. 'Nov'. 'Mai'. 'Mier'. $year. $year.

imagini etc. fie în mod explicit (apelat din cadrul paginii printr-o directivă specială). programele CGI trebuie apelate (implicit sau explicit) din cadrul paginilor Web.2.1. returnând.1 Primele script-uri CGI Standard de facto pentru interacţiunea clienţilor Web cu serverele Web. Cele mai multe script-uri CGI sunt concepute pentru a procesa datele introduse în for- mulare. eventual. denumit în mod uzual script. rezultatele către navigator. XML. Script-uri CGI în Perl 2. Antetul trimis serverului de către programul CGI va respecta specificaţiile MIME. iar programul CGI va genera o pagină Web conţinând maximul dintre ele. Common Gateway Interface se află în prezent la versiunea 1. Programele CGI pot oferi su- port de asemenea la autentificarea utilizatorilor pe partea server. iar script-ul. con- ţinând de exemplu Content-type: text/html (document HTML sau XHTML) sau Content-type: image/jpeg (imagine JPEG) ori Content-type: text/plain (text obişnuit). CGI conferă inter- activitate paginilor Web.) spre a fi tri- mise navigatorului Web la ieşirea standard (stdout). 46 . se execută pe serverul WWW. fie la preluarea informaţiilor aflate în cadrul câmpurilor unui formular interactiv sau coordonatelor unei zone senzitive (image map). Uzual. va prelua conţinutul acelui formular şi-l va prelucra. Programului CGI i se vor transmite în diverse variabile de mediu sau de la intrarea standard informaţii referitoare la datele de procesat sau privitoare la clientul care a iniţiat cererea. Pentru a fi efective. în funcţie de metoda de transfer utilizată. un script CGI va fi invocat din cadrul unui formular HTML la apă- sarea butonului de trimitere a datelor către server (butonul de tip submit). • programul generează antete care permit serverului Web să interpreteze corect ieşirea script-ului (folosindu-se specificaţiile protocolului HTTP). Un program CGI. Regulile care trebuie respectate la conceperea unui script CGI sunt următoarele: • programul scrie datele (marcaje HTML. documentele HTML putând astfel să-şi modifice în mod dina- mic conţinutul şi să permită prelucrări sofisticate de date. invocat şi executat de serverul Web. Un formular se defineşte în XHTML folosindu-se marcatori specifici pentru afi- şarea conţinutului şi introducerea datelor de către client. Să presupunem că avem următorul exemplu în care un utilizator introduce prin inter- mediul unui formular două numere întregi.

De exemplu.cgi" method="GET"> <p>Vă rugăm. script-ul poate fi lo- calizat desigur şi prin intermediul unui URL relativ). 47 . se va genera o pereche nu- me_de_câmp=valoare delimitată de caracterul "&".infoiasi. precedat de caracterul procent ("%"). Desigur. însemnând faptul că se foloseşte serverul pe care se găseşte pagina conţinând formularul. o cerere către serverul Web aflat la adresa dată de URL-ul http://www. Formularul XHTML ar putea fi: <form action="http://www. Pentru fiecare câmp al formularului.ro (adresa este preluată din valoarea atributului action al elementului <form>. navigatorul va trimite. pentru a trimite textul Cina de la Maxim's se va folosi codificarea Cina+de+la+Maxim%27s. în loc de o adresă absolută. introducând numerele 7 şi 4 şi acţionând butonul etichetat "Află maxi- mul". în cazul nostru http://www.infoiasi.infoiasi. Presupunând că în cele două câmpuri ale formularului (purtând numele nr1 şi respectiv nr2) am introdus valorile 7 şi 4 respectiv şi am apăsat butonul de tip submit (etichetat cu "Află maximul"). prin intermediul protocolului HTTP.ro/cgi-bin/max.ro/cgi-bin/max. vom primi o pagină Web (un document marcat în XHTML) care va afişa textul "Maximul dintre 7 şi 4 este numărul 7" (vezi figura). putea fi specificată o cale relativă. Spaţiile vor fi substituite de semnul plus ("+").cgi?nr1=7&nr2=4 folosindu-se o codificare specială. navigatorul construieşte un URL având ca sufix informaţii despre datele introduse în câmpurile formularului. în hexazecimal. introduceţi două numere:</p> <input name="nr1" size="3" /> <input name="nr2" size="3" /> <br /> <input type="submit" value="Află maximul" /> </form> De exemplu. iar caracterele speciale (ca de exem- plu slash-ul sau apostroful) vor fi înlocuite de codul lor numeric. Atunci când se trimite cererea HTTP.

cgi) şi-i va pasa datele furnizate de sufix.cgi aflat la /home/httpd/cgi-bin". Astfel. daemonul HTTP (adică serverul Web. în mod uzual).ro/cgi-bin/max.infoiasi.infoiasi.ro următoarea acţiune: "invocă programul max. fişiere JavaScript etc. Introducerea datelor în formular şi obţinerea rezultatului furnizat de script-ul CGI după acţionarea butonului de tip submit Serverul spre care cererea a fost expediată (în cazul sitului www. configuraţia serverului defineşte unde sunt stocate în cadrul sistemului de fişiere directoarele şi fişierele CGI. alături de directorul html ori public_html unde se memorează documentele (HTML. fişierele sale fiind stocate (în cazul unui sistem UNIX/Linux) de obicei în directorul /var/www/.cgi va însemna pentru serverul Web aflat la adresa www. de după semnul întrebării (adică şirul nr1=7&nr2=4). regăsit ca proces de fundal sub numele httpd) rulează pe maşină sub auspicii de utilizator fictiv (din raţiuni de secu- ritate ca nobody sau apache. se află şi directorul cgi-bin unde ar trebui să fie stocate toate fişierele (script-urile) CGI apelate din cadrul paginilor Web. Fişierele de configurare a serverului în mod uzual se regăsesc în directorul /etc/httpd/conf/. Aşadar URI-ul http://www. Aici. Tipic.ro un ser- ver Apache rulând pe un sistem Linux) va procesa datele recepţionate conform regulilor proprii.) unui sit Web. fişiere multimedia.infoiasi. 48 . serverul va invoca script-ul CGI specificat (în acest caz max. în loc să trimită către navigatorul Web care a iniţiat cererea HTTP un document HTML sau un fişier de alt tip. CSS. De cele mai multe ori.

Pentru formularele utilizând metoda POST. Acţiunea de invocare va avea o semantică diferită în funcţie de script-ul CGI conceput. 49 . • Metoda POST este utilă în situaţiile în care avem de trimis script-ului CGI spre prelucrare un volum mai mare de date (de exemplu. în cazul exemplului de mai sus valoarea acestei variabile va fi nr1=7&nr2=4). pentru a permite execuţia de programe CGI. Pentru un script Perl.g. datele pasate script-ului vor putea fi accesate de la intrarea standard (stdin). parole) care nu trebuie să apară în componenţa URI-ului transmis serverului Web.cgi nu are nici o relevanţă în general. a informaţiilor trimise va fi disponibilă în variabila de mediu CONTENT_LENGTH. • Pentru metoda GET (metoda implicită de transfer a datelor de la un na- vigator Web). de fapt. Procesul de invocare a unui script CGI Extensia de fişier . dar pot exista diverse reguli de numire a fişierelor CGI executabile dependente de server sau de sistemul de operare pe care rulează. iar lungimea. serverul va invoca un interpretor Perl (în cazul Apache. script-ul CGI va primi în mod diferit şirul de interogare. În funcţie de metoda de transfer folosită. De multe ori este util ca într-un script CGI să detectăm metoda de transfer pentru a prelua datele în mod corespunzător. în octeţi. Pentru aceasta va trebui să se testeze valoarea varia- bilei de mediu REQUEST_METHOD. serverul Apache se va folosi de serviciile modulului mod_cgi). informaţiile din şirul de interogare (cele de după delimitatorul "?") vor fi disponibile într-o variabilă de mediu purtând numele QUERY_STRING. Ast- fel. Pentru ca un script CGI să poată fi invocat trebuie să poată fi citit şi exe- cutat de utilizatorul fictiv sub care îşi desfăşoară activitatea serverul Web. un modul special mod_perl. conţinu- tul unei scrisori ori al unui fişier) sau informaţii confidenţiale (e.

} 50 . # trimitem codul HTML. <html> <head> <title>Salut!</title> </head> <body bgcolor="white" text="blue"> <p>Salut!</p> </body> </html> HTML Ca orice alt script CGI conceput în alt limbaj.). orice script CGI trebuie să afişeze la ieşirea standard câmpul HTTP Content-type. # (folosim facilitatea "here") print <<HTML. cel mai simplu script este următorul: #!/usr/bin/perl # trimitem antetul HTTP print "Content-type: text/html\n\n". nici script-urile CGI concepute în Perl nu fac excepţie. Acest lucru se poate rezolva prin accesa- rea tabloului asociativ ENV: #!/usr/bin/perl # trimitem antetul HTTP print "Content-type: text/plain\n\n". După cum am văzut mai sus. foreach $variabila (sort keys %ENV) { print "$variabila: $ENV{$variabila}\n". un script CGI scris în Perl va avea acces la variabilele de mediu furnizate de serverul Web. arhive. Astfel. documente XML etc. înainte de a trimite spre navigator pagini Web sau alte ti- puri de informaţii (multimedia. Desigur. print "Variabilele de mediu disponibile:\n".

$valoare. # preluam perechi 'camp=valoare' local(@perechi) = split('&'. implementând funcţia analiza_parametri() care va returna un tablou asociativ având drept chei numele câmpurilor şi ca valori valorile acestor câmpuri: sub analiza_parametri { # variabile locale local($interogare) = @_. %parametri). Ne propunem să scriem un script Perl simplu care preia dintr-un formular valorile a două numere întregi şi returnează clientului Web maximul dintre cele numere. $interogare).Preluarea datelor prin metoda GET Pentru a accesa datele transmise prin intermediul metodei GET va trebui să le preluăm ca URI codificat din variabila de mediu QUERY_STRING. local($parametru. Script-ul Perl va prelua din variabila de mediu QUERY_STRING şirul de interogare codi- ficat: $interogare = $ENV{'QUERY_STRING'}.pl. $value = &unescape($value). introducând numerele 3 şi 1 şi acţionând butonul "Află maximul".cgi" method="GET"> <p>Introduceti două numere: <input type="text" name="nr1" size="3" /> <input type="text" name="nr2" size="3" /> <br /> <input type="submit" value="Află maximul" /> </form> De exemplu. Vom scrie aşadar următorul formular XHTML: <form action="max. valoare) şi apoi să preluăm valorile fiecărui câmp al formularului. vom primi o pagină Web care va afişa textul "Maximul dintre 3 şi 33 este: 33". # decodificam valorile $parametru = &unescape($parametru). $valoare) = split('='). 51 . Va trebui să divizăm acest şir de caractere în perechi (nume de câmp. foreach (@perechi) { # preluam valoarea si numele de camp ($parametru. Acest lucru se realizează în maniera urmă- toare.

= "$. if ($nr1 > $nr2) { $max = $nr1. } 52 . } } return %parametri. # preluam sirul de interogare # din variabile de mediu QUERY_STRING $interogare = $ENV{'QUERY_STRING'} || die "Sir de interogare vid!\n". # preluam valorile parametrilor $nr1 = $parametri{'nr1'}. # %HH devine caracter ASCII $sir =~ s/%([0-9A-Fa-f]{2})/pack("c". } else { $parametri{$parametru} = $valoare. } Script-ul complet max. return $sir. Content-type: text/html <html><head><title>Maxim</title></head> <body> <h2>Maximul a doua numere</h2> <hr> HTML .$valoare". %parametri = &analiza_parametri($interogare). # memoram in tabloul 'parametri' if ($parametri{$parametru}) { $parametri{$parametru} .cgi este următorul: #!/usr/bin/perl -w # calculeaza maximul a doua numere # (se utilizeaza metoda GET) print <<HTML. iar "%" urmat de două cifre în baza 16 va fi substituit de caracterul ASCII corespunzător): sub unescape { local($sir) = @_. hex($1))/ge. } Mai rămâne să decodificăm şirurile de caractere ("+" va deveni spaţiu. $nr2 = $parametri{'nr2'}.pl. # "+" devine spatiu $sir =~ tr/+/ /.

local($parametru. $value = &unescape($value). foreach (@perechi) { # preluam valoarea si numele de camp ($parametru. $valoare) = split('='). %parametri). return $sir. # decodificam valorile $parametru = &unescape($parametru). hex($1))/ge. # %HH devine caracter ASCII $sir =~ s/%([0-9A-Fa-f]{2})/pack("c". } 53 . # am terminat exit. $interogare).= "$. } else { $parametri{$parametru} = $valoare. sub analiza_parametri { # variabile locale local($interogare) = @_. # memoram in tabloul 'parametri' if ($parametri{$parametru}) { $parametri{$parametru} . # "+" devine spatiu $sir =~ tr/+/ /. # preluam perechi 'camp=valoare' local(@perechi) = split('&'. } print "<p>Maximul dintre $nr1 si $nr2 este: $max</p>\n". } # functie de decodificare sub unescape { local($sir) = @_.else { $max = $nr2. print <<HTML. $valoare. } } return %parametri.$valoare". <hr> </body> </html> HTML .

$ENV{'CONTENT_LENGTH'}). die "Sir de interogare vid!\n" unless $interogare. Content-type: text/html <html><head><title>Maxim</title></head> <body> <h2>Maximul a doua numere</h2> <hr> HTML .Preluarea datelor prin metoda POST Trimiţând valorile câmpurilor formularului prin metoda POST. $nr2 = $parametri{'nr2'}. } print "<p>Maximul dintre $nr1 si $nr2 este: $max</p>\n". } else { $max = $nr2. %parametri = &analiza_parametri($interogare). print <<HTML. <hr> </body> </html> HTML 54 . codul script-ului fiind (rutinele analiza_parametri() şi unescape() au fost omise): #!/usr/bin/perl -w # calculeaza maximul a doua numere # (se utilizeaza metoda POST) print <<HTML. desigur. # preluam sirul de interogare de la # intrarea standard read(STDIN. nu vom mai consulta variabila de mediu QUERY_STRING. if ($nr1 > $nr2) { $max = $nr1. vor trebui decodificaţi. Pentru decodificare vom folosi rutinele pre- zentate mai sus. $interogare. ci vom citi de la intrarea standard CONTENT_LENGTH octeţi care. # preluam valorile parametrilor $nr1 = $parametri{'nr1'}.

. # am terminat exit. 55 .

# trimitem antetul HTTP print header(). p('Un paragraf.. Un alt avantaj este dat de posibilitatea de a depana script-urile CGI rulându-le direct de la prompt-ul Linux. # afisam antetul paginii Web print start_html(-title => "Un salut"). # afisam finalul de document print end_html().2 Modulul CGI Pentru realizarea comodă de script-uri CGI în Perl. utilizat în special pentru generarea şi procesarea formularelor şi a cookie-urilor. Următorul exemplu foloseşte paradigma procedurală: #!/usr/bin/perl # utilizam modulul CGI in forma standard use CGI qw/:standard/. Cele două paradigme nu diferă decât prin modul de acces la funcţionalităţile modulu- lui: via funcţii în primul caz şi via metode în al doilea. # afisam diferite elemente HTML print h1('Salut!'). din perspectiva orientată-obiect. este pus la dispoziţie modulul CGI. Modalităţi de utilizare Putem folosi modulul CGI prin intermediul a două paradigme de programare: funcţiona- lă (procedurală) şi obiectuală.').2. cât şi prin metoda POST. Acelaşi script. Modulul CGI poate fi utilizat pentru preluarea datelor transmise atât prin metoda GET. Acest mo- dul oferă un obiect generic CGI pentru acces la variabile de mediu.. # instantiem obiectul CGI $c = new CGI. pentru procesarea lor şi stocarea rezultatelor. în loc de a fi invocat prin intermediul serve- rului Web. 56 . fără a concepe programe separate pen- tru fiecare metodă în parte. este: #!/usr/bin/perl # utilizam modulul CGI use CGI.

vom scrie.. deoarece câmpul prieteni poate conţine elemente multiple ale unui marcator <select>. În prima variantă. Atunci când dorim să asignăm o nouă valoare unui parametru. # afisam finalul de document print $c->end_html(). apelând metoda param(): @parametri = $c->param. $culoare = $c->param('culoare'). Preluarea parametrilor Cele mai uzuale utilizări ale modulului CGI sunt cele în care sunt implicate formularele Web ale căror valori de câmpuri trebuie prelucrate comod. Dacă dorim să preluăm valoarea unui anumit parametru vom folosi una dintre con- strucţiile: @prieteni = $c->param('prieteni'). $c->p('Un paragraf. Procesarea antetului HTTP Aşa cum am văzut. un script CGI trebuie să trimi- tă obligatoriu antetul HTTP. Metoda header() poate fi folosită şi pentru a seta alte câmpuri HTTP: 57 . -value=>'rosu'). rezultatul este preluat de un tablou.. # afisam diferite elemente HTML print $c->h1('Salut!'). # afisam antetul paginii Web print $c->start_html(-title => "Un salut"). Varianta procedurală este: $o_culoare = param('culoare'). Acest lucru se realizează prin intermediul metodei sau func- ţiei header(): # trimite Content-type: image/gif print $c->header('image/gif').# trimitem antetul HTTP print $c->header(). înainte de a genera cod-sursă HTML.'). de exemplu: $c->param(-name=>'culoare'. Pentru a prelua toţi parametrii pasaţi script-ului ne putem sluji de un tablou.

• user_agent() identifică numele şi versiunea agentului-utilizator (navigatorului. De asemenea. dar se returnează numele simbolic al calculatorului client. Acest lucru permite folosirea unor protocoale noi. • request_method() furnizează metoda HTTP utilizată (GET. else print $c->redirect('/en/index. POST sau HEAD). +30s (după 30 de secunde). Pentru atributul -expires pot fi specificate valori de timp precum now (acum). în funcţie de sistemul de opera- re al clientului: #!/usr/bin/perl 58 .html'). trimise câmpuri definite de utilizatori. fără a trebui să actualizăm mo- dulul CGI. • remote_addr() furnizează adresa IP a calculatorului client care a invocat script-ul. se pot invoca diverse metode care să ofere valorile variabilelor de mediu specifice HTTP. • remote_host() ca mai sus. # parametru-utilizator -Cost => '$ 0. se poate folosi metoda redirect() pentru a redirecta navigatorul către altă locaţie: # redirectare in functie de limba if ($limba eq 'ro') print $c->redirect('/ro/index. Astfel.01'). # codul de stare HTTP -status => '402 Payment Required'.print $c->header( # Content-type -type => 'image/png'. Iată un exemplu în care redirectăm automat browserul. +15m (după 15 minute). Pot fi. +5h (după 5 ore) sau +3M (după 3 luni). # timpul de expirare -expires => '+3d'. de cele mai multe ori) folosit pe calculatorul client. Mai mult.html'). Sunt acceptate şi valori negative. în exemplul de mai sus Cost. putem apela metode precum: • query_string returnează şirul de interogare CGI. de asemenea.

} print "Location: $url/$pag\n\n". use CGI qw/escape unescape/.html' || /.'). print unescapeHTML($sir).. print unescape($sir).infoiasi. 59 . În loc de user_agent() puteam folosi $ENV{HTTP_USER_AGENT}.html' || /HP-UX/ && 'hpux.use CGI. • unescapeHTML() converteşte un şir de caractere conţinând entităţi HTML în şir obişnuit. $url = 'http://www. desigur.html' || /SunOS/ && 'sunos.html'. • escapeHTML() converteşte un şir de caractere. for (CGI::user_agent()) { # simularea unui 'switch' $pag = /Linux/ && 'linux. $sir = escapeHTML('Un sir mai <mic>.html' || /Win|MSIE/ && 'win.*/ && 'generic.ro'.. substituind orice caracter HTML ilegal prin entitatea corespunzătoare. $sir = escape('~/:#?'). use CGI qw/escapeHTML unescapeHTML/.html' || /Mac/ && 'macos. • unescape() converteşte un şir codificat CGI în reprezentarea sa normală. Alte funcţii utile oferite de modulul CGI sunt: • escape() converteşte un şir de caractere în codificarea utilizată de URI- urile CGI.

pm permite redirectarea mesajelor de eroare către navigator. • MiniSvr. De asemenea. • BasePlus. De menţionat aici şi faptul că serverul Apache incorporează direct interpretorul Perl prin intermediul modulului mod_perl.Modulele CGI În fapt. în loc de a scrie cod HTML.pm este responsabil cu analiza şi procesarea cererilor HTTP. astfel încât timpul de execuţie a script-urilor CGI concepute în Perl să fie minim.pm este utilizat pentru a genera antete HTTP. modulul CGI este suplinit şi de următoarele module: • Base. spre un fişier jurnal sau un fişier utilizator. serverul Web va lansa o nouă instanţă a interpretorului implementat de mod_perl.pm extinde modulul precedent. adăugând facilităţi precum upload de fişiere. 60 .pm este folosit pentru a genera mai uşor formulare Web. • Form. • Request. accelerându-se timpul de execuţie a script-urilor.pm oferă funcţionalităţile de bază pentru dezvoltarea de script-uri CGI. • Response.pm implementează un server HTTP minimal. • Carp. Pentru fiecare script Perl invocat. la iniţializarea serverului (pornirea daemonului httpd) putem configura mod_perl astfel încât să se încar- ce modulele Perl dorite în acest moment şi nu la prima lor utilizare.

print "Selectati anul: <select name=\"an\">\n". Acest script nu foloseşte modulul CGI şi poate fi invocat indiferent de metoda HTTP utilizată (pentru aceasta vom testa valoarea variabilei de mediu REQUEST_METHOD). #!/usr/bin/perl -w # afiseaza calendarul. %interogare = &furnizeaza_interogarea. folosind sau nu modulul CGI. Pentru generarea calendarului se va recurge la comanda UNIX cal. # preluam anul if ($interogare{'an'}) { $an = $interogare{'an'}. } # antetul paginii print <<HTML. # va fi selectat implicit anul curent foreach $un_an (@ani) { 61 .2. @ani = (1990.. Content-type: text/html <html><head><title>Calendar</title></head> <body text="blue" bgcolor="white"> <h3 align="center">Calendarul pentru anul $an </h3> HTML .2033). Calendar Începem cu un exemplu clasic al unui script care afişează calendarul unui an (furnizat de utilizator sau anul curent).3 Exemple de script-uri Furnizăm în continuare o serie de exemple de script-uri CGI. } else { chop($an = `date +%Y`). # folosind comanda UNIX 'cal' # (scriptul va fi functional indiferent # de metoda HTTP folosita: GET sau POST) $CAL = '/usr/bin/cal'. # cream formularul din care se va prelua anul dorit print "<form method=\"POST\">\n".

# daca e GET. $interogarea. preluam datele din variabila de mediu if ($metoda eq 'GET') { $interogarea = $ENV{'QUERY_STRING'}. <pre> $calendarul </pre> <hr> </body> </html> HTML . } # executam comanda 'cal' pasindu-i ca parametru anul dorit chop($calendarul = `$CAL $an`). # selectam implicit anul curent if ($un_an == $an) { print " selected". # butonul de trimitere print '<p><input type="submit" value="Afiseaza calendarul">'. print "<option". # rezultatul returnat de 'cal' # este afisat preformatat cu <pre> print <<HTML. } print "</select>\n". exit 0. # am terminat exit. # preluam metoda cererii local($metoda) = $ENV{'REQUEST_METHOD'}. # rutinele de procesare a interogarii sub furnizeaza_interogarea { local($interogarea). # dace e POST. preluam de la intrarea standard } elsif ($metoda eq 'POST') { read(STDIN. } print ">$un_an</option>\n". } 62 . print "</form>\n<hr>\n". $ENV{'CONTENT_LENGTH'}). # ne pregatim de afisarea calendarului # verificam anul unless ($an=~/^\d{4}$/) { print "<p style='color:red'>Anul trebuie sa aiba 4 cifre</p>\n".

daca nu e furnizata nici o data return () unless $interogarea.cgi este următoarea: 63 . vom genera un formular HTML utilizând capabilităţile puse la dispoziţie de modulul CGI.$valoare". $value = &unescape($value). # decodificam valorile $parametru = &unescape($parametru). foreach (@perechi) { # preluam valoarea si numele de camp ($parametru. } else { $parametri{$parametru} = $valoare.pl. cuvintelor sau caracterelor conţinutului său. Pen- tru aceasta. # "+" devine spatiu $sir =~ tr/+/ /. } sub analiza_parametri { # variabile locale local($interogare) = @_. prin preluarea de pe calculatorul client a unui fişier în vederea numărării liniilor. # iesim. Sursa acestui script Perl. # %HH devine caracter ASCII $sir =~ s/%([0-9A-Fa-f]{2})/pack("c". # procesam interogarea return &analiza_parametri($interogarea). %parametri). } Numărarea liniilor unui fişier Acest exemplu ilustrează acţiunea de upload. # memoram in tabloul 'parametri' if ($parametri{$parametru}) { $parametri{$parametru} . $valoare) = split('='). return $sir.= "$. hex($1))/ge. } } return %parametri. } # functie de decodificare sub unescape { local($sir) = @_. $interogare). $valoare. # preluam perechi 'camp=valoare' local(@perechi) = split('&'. denumit numara. local($parametru.

# genereaza un formular print # formular eteroge $cerere->start_multipart_form. -values=>\@tipuri. # definim tipurile de calcule pe care le oferim my(@tipuri) = ('numara linii'.#!/usr/bin/perl use CGI. # afiseaza butoanele standard # de tip 'reset' si 'submit' $cerere->reset. END . "<br>". print <<END. -defaults=>\@tipuri). &numara($cerere). } 64 . print $cerere->end_html. &interogare($cerere). "Introduceti numele fisierului:". # instantiem obiectul CGI $cerere = new CGI. $cerere->filefield(-name => 'fisier'. $cerere->submit(-label=>'Numara'). <h3>Numara</h3> <p>Selectati <b>Browse</b> pentru a alege un fisier text. # am terminat exit. $cerere->end_form. 'numara caractere'). "<p>". apoi apasati butonul <b>Numara</b>. $cerere->checkbox_group(-name=>'numarare'. 'numara cuvinte'. -size => 30). print $cerere->header. # afiseaza formularul de interogare a utilizatorului sub interogare { my($cerere) = @_.

print "<b>Caractere:</b> $caract<br>\n" if $num{'numara caractere'}. $DIR_IMAGINI = 'img'. print "<b>Cuvinte:</b> $cuv<br>\n" if $num{'numara cuvinte'}. if (%num) { print "<b>Linii:</b> $linii<br>\n" if $num{'numara linii'}. # procesam continutul fisierului while (<$fisier>) { $linii++. # constante folosite pentru specificarea # directoarelor care contin imagini $DIR_RADACINA = '.# numara linii.'. } # vedem ce tip de numarare a fost selectat grep($num{$_}++. GIF (Graphical Interchange Format) sau PNG (Portable Network Graphics). 65 . "o metoda de numarare. } } # sfirsit de if } Afişarea unei imagini aleatoare Ne propunem să scriem un script care la fiecare rulare să afişeze o altă imagine preluată aleatoriu dintr-un director cu fişiere grafice în formatele JPEG (Joint Picture Experts Group). } else { print "<b>Nu ati selectat nici " . $caract += length($_). Codul sur- să al acestui script simplu este: #!/usr/bin/perl # afiseaza continutul unui fisier grafic ales aleatoriu use CGI qw/:standard/. cuvinte. $cerere->param('numarare')). print "<h3>Fisier: <tt>$fisier</tt></h3>\n". # procesam datele introduse if ($fisier = $cerere->param('fisier')) { print "<hr>\n". $cuv += @cuv = split(/\s+/). caractere sub numara { my($cerere) = @_.</b>\n".

die "eroare la selectarea imaginii" unless $imagine. # constante utilizate in cadrul formularului # culori de fundal dorite @culori=qw/gray coral bisque beige gold green lime linen orchid seashell sienna silver wheat/. # preluam vechile preferinte din cookie-ul "preferinte" %preferinte = $c->cookie('preferinte'). $preferinte{'nume'} = $c->param('nume') if $c->param('nume'). #!/usr/bin/perl use CGI. La invocarea script-ului se verifică dacă preferinţe- le există şi se modifică înfăţişarea paginii în concordanţă cu acestea. culoarea de fundal a paginii şi mărimea fontului im- plicit. Utilizatorul va putea să introducă prin intermediul unui formular interactiv numele său.". # alegem imaginea $imagine = $imagini[rand(@imagini)]. # redirectam navigatorul spre imaginea aleasa print redirect("$DIR_IMAGINI/$imagine"). # alegem culoarea implicita 'silver' daca nu exista $preferinte{'culoare'} = 'silver' unless $preferinte{'culoare'}. # instantiem obiectul CGI $c = new CGI. # preluam intr-un tablou fisierele JPEG. $preferinte{'marime'} = $c->param('marime') if $c->param('marime'). Memorarea preferinţelor utilizatorilor În cadrul acestui script vom putea observa capabilităţile oferite de modulul CGI în ceea ce priveşte manipularea cookie-urilor.7).gif.chdir "$DIR_RADACINA/$DIR_IMAGINI" or die "directorul de imagini e inaccesibil..png}>. 1. # dimensiunea fontului @marime=("<implicit>". GIF si PNG @imagini = <*. # preluam noile preferinte ale utilizatorului prin # inspectarea valorilor transmise prin formular $preferinte{'culoare'} = $c->param('culoare') if $c->param('culoare').{jpg. 66 . Aceste preferinţe vor fi stocate în cookie-uri pe maşina client a utilizatorului până la următoarea vizită sau maxim 30 de zile.

# modificam parametrii cookie-ului astfel incit # sa fie persistent si sa reflecte noile preferinte $un_cookie = $c->cookie(-name=>'preferinte'. <h3 align="center">$title</h3> <hr> <p align="justify"> Modificati modul de aparitie al paginii completind formularul de mai jos. -values=>\@marime. 67 . "Culoarea de fundal preferata: ". nume de utilizator si marimea fontului print $c->start_html(-title=>$title. -expires=>'+30d'). incluzind numele utilizatorului $title = $preferinte{'nume'} ? "Pagina lui $preferinte{nume}!" : "Pagina utilizatorului". # stabilim marimea fontului print "<basefont size=$preferinte{marime}>\n" if $preferinte{'marime'} > 0. "Prenumele d-voastra: ". $c->popup_menu(-name=>'marime'. "Marimea fontului: ". # trimitem cookie-ul print $c->header(-cookie=>$un_cookie). Preferintele dumneavoastra vor fi valabile timp de maxim 30 de zile. $c->start_form. -bgcolor=>$preferinte{'culoare'}). # vom crea pagina HTML.</p> END . -default=>$preferinte{'marime'}). "<br>". # generam titlul paginii. -default=>$preferinte{'nume'}. -default=>$preferinte{'culoare'}). # vom crea formularul de preferinte print join("\n". $c->popup_menu(-name=>'culoare'. oferind posibilitatea # de a schimba preferintele de # culoare. print <<END. "<hr>". -size=>30). -value=>\%preferinte. -values=>\@culori. $c->textfield(-name=>'nume'.

Soluţii profesioniste de implementare.infoiasi. Iaşi. Situri Web la cheie. $c->submit(-label=>'Memoreaza preferintele'). Polirom. Alte exemple.). relativ mai complexe..ro/~cgi/ ƒ S. Buraga et al. Programare Web în bash şi Perl. sunt disponibile în volumele: ƒ S. Polirom. Buraga (coord.ro/~busaco/books/webapps/ 68 . Iaşi. 2004: http://www. "<hr>")."<br>".infoiasi. 2002: http://www.

orele de acces maxim. pentru un vizitator din România se va afişa un citat în limba română). Se vor genera şi statistici referitoare la cele mai cău- tate nume. Se vor prevedea autentificarea şi salvarea preferinţelor utilizatorilor. planuri de situ- aţie şi având posibilităţi de căutare. imagine interioară.3. paginile accesate cel mai des etc. Să se realizeze o aplicaţie Web implementată în Perl care să proceseze informaţiile privitoare la cursele aeriene furnizate de o anumită companie. dotare etc. Utilizatorii vor putea formula cerinţe pentru nume. 7. 3. Statisticile vor cuprinde grafice cu zonele de unde au fost făcute cereri. Să se proiecteze şi implementeze un sit Web pentru alegerea de către părinţi a numelor de copii. luni. pe diverse teme (peisaje. Să se scrie un script CGI care să afişeze un citat celebru ales aleatoriu dintr-o listă. Să se conceapă o aplicaţie Web pentru vizualizarea diferitelor informaţii (utilizare.) despre încăperile care compun clădirile unei anumite organizaţii. programarea de întâlniri etc. opere de artă etc. cu şi fără ajutorul modulului CGI. Agenda va include un mini-editor de texte. 2. includerea de legături Web. figuri de personalităţi. Să se realizeze un sit Web pentru vizualizarea şi trimiterea de ilustrate electronice. permiţând realizarea de adnotări pe zile. Se vor realiza mai multe variante. Teme propuse 1. un calculator. 6. Prin intermediul unor script-uri Perl. în funcţie de localizarea geografică a vizitatorilor (de exemplu. incluzând punerea la dispoziţia utilizatorului de hărţi. Să se implementeze o aplicaţie WWW care furnizează diverse statici privind acce- sul la documentele de pe un sit. litera de început etc. 5. Să se conceapă în limbajul Perl un script CGI care să fie utilizat pentru evaluarea expresiilor matematice cu paranteze. folosind datele conţinute de fişierul access_log generat de serverul Web. capacitate. 69 . să se simuleze o agendă de birou. un calendar şi un ceas electronic. 8. număr de silabe. în funcţie de sex.). oraşe celebre. 4. săptămâni.

Buraga. Polirom. D. Iaşi.ro/~cgi/ 2.ro/~linux/ 6. * * *. Perl: http://www.infoiasi. Iaşi. Situri Web la cheie. Trăuşan-Matu et al. 2002: http://www.com/ 8.org/ 70 .com/ 10.edu/cgi/intro.. Ş. Acostăchioaie. Bucureşti.ro/~busaco/books/webapps/ 4. S. Matrix Rom. Polirom. Acostăchioaie. Polirom. * * *. 2005: http://www.). Polirom. Programare Web în bash şi Perl.infoiasi. Buraga et al. 2004: http://www. * * *.html 9. CGI Resources: http://www. Buraga (coord.w3. Introduction to CGI: http://hoohoo. 2001 3. Proiectarea siturilor Web (ediţia a II-a).adt. 2005: http://www.ro/~design/ 5.uiuc. Utilizare Linux. 2004: http://www. Iaşi.cgi-resources. S.. Iaşi. S. S.Resurse bibliografice (în ordinea relevanţei) 1.perl.ro/admin/ 7. Buraga. Polirom. Soluţii profesionale de implementare. Administrarea sistemelor Linux (ediţia a III-a).ncsa. Consorţiul Web: http://www. Prelucrarea documentelor folosind XML şi Perl.infoiasi. Iaşi. * * *. D.infoiasi.