# Exemplele prezentate scot în evidență comportamentul # unor combinații de metacaractere în expresii REGEX și modul # în care sunt exploatate variabilele speciale în diverse situații. # Comportamentul de tip Greedy: As Many As Possible (longest match). # Comportamentul de tip Lazy: As Few As Possible (shortest match). # Variabilele $1..$n se inițializează în funcție de numărul de grupuri stabilite. # Variabilele $-[1]..$-[n] dețin poziția de început a fiecărui grup în cadrul șirului. # Variabilele $+[1]..$-[n] dețin poziția de afârșit a fiecărui grup în cadrul șirului. # Variabilele $1..$n sunt utile doar atunci când numărul de grupuri este antecunoscut. #=pod $secv = 'accgtgtttaccgtttcccacgtttac'; print "\nEXEMPLUL (1)\n"; print "În secvența: $secv\n"; print 'Expresia REGEX: /(a.c)(.+?)(t.t)(.+?)(t.t)/'," determină:\n"; if ($secv =~ /(a.c)(.+?)(t.t)(.+?)(t.t)/){ print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print 'Variabilele $1, $2, $3, $4, $5, ',"s-au potrivit cu: $1 , $2 , $3, $4, $5\n"; print 'Variabilele $-[1], $-[2], $-[3], $-[4], $-[5] au valorile: ',"$-[1] $-[2] $-[3] $-[4] $-[5]\n"; print 'Variabilele $+[1], $+[2], $+[3], $+[4], $+[5] au valorile: ',"$+[1] $+[2] $+[3] $+[4] $+[5]\n"; } #=cut # Același exemplu ca cel anterior însă cuplat cu modificatorul g (global). # Dacă analizăm rezultatul, el este similar și ar putea conduce la concluzia că # mecanismul global nu funcționează. El identifică mereu accgtgtttaccgttt deși # ar trebui să poată identifica și accgtttcccacgttt din poziția 9. # TREBUIE AVUT ÎN VEDER că poziția de la care continuă se află mereu # la capătul șirului care a făcut match, adică accgtgtttaccgttt. # Căutarea nu continuă niciodată din interiorul acestui șir, # din această cauză soluția nu cuprinde și situația accgtttcccacgttt. #=pod $secv = 'accgtgtttaccgtttcccacgtttac'; print "\nEXEMPLUL (2)\n"; print "În secvența: $secv\n"; print 'Expresia REGEX: /(a.c)(.+?)(t.t)(.+?)(t.t)/g'," determină\n"; while ($secv =~ /(a.c)(.+?)(t.t)(.+?)(t.t)/g){ print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print 'Variabilele $1, $2, $3, $4, $5, ',"s-au potrivit cu: $1 , $2 , $3, $4, $5\n"; } #=cut # ATENȚIE la formularea expresiei în exemplul următor: # (a.c)(.+)(t.t)(.+)(t.t) comparativ cu (a.c)(.+?)(t.t)(.+?)(t.t) folosită la cel anterior. # Rezultatul poate fi explicat de felul în care se comportă metacaracterele. # Metacaracterul + în paranteze () are comportament de tip Greedy: As Many As Possible (longest match) # Combinația +? în paranteze are comportament de tip Lazy: As Few As Possible (shortest match) #=pod $secv = 'accgtgtttaccgtttcccacgtttac'; print "\nEXEMPLUL (3)\n"; print "În secvența: $secv\n"; print 'Expresia REGEX: /(a.c)(.+)(t.t)(.+)(t.t)/'," determină\n"; if ($secv =~ /(a.c)(.+)(t.t)(.+)(t.t)/){ print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print 'Variabilele $1, $2, $3, $4, $5, ',"s-au potrivit cu: $1 , $2 , $3, $4, $5\n"; } #=cut # Același exemplu ca cel anterior cu modificatorul g (global) # Explicația rezultatului este similară cu cea de la EXEMPLUL (3). # De asemenea, apare aceeași problemă evidențiată în EXEMPLUL (2). Și în acest caz s-ar # fi putut identifica accgtttcccacgttt începând cu poziția 9 a șirului. #=pod $secv = 'accgtgtttaccgtttcccacgtttac'; print "\nEXEMPLUL (4)\n"; print "În secvența: $secv\n"; print 'Expresia REGEX: /(a.c)(.+)(t.t)(.+)(t.t)/g'," determină\n"; while ($secv =~ /(a.c)(.+)(t.t)(.+)(t.t)/g){ print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print 'Variabilele $1, $2, $3, $4, $5, ',"s-au potrivit cu: $1 , $2 , $3, $4, $5\n"; } #=cut # Acest exemplu introduce funcția pos() care returnează # poziția ultimului match în contextul unei expresii REGEX de tipul m//g # Pentru mai multe detalii vezi: https://perldoc.perl.org/functions/pos # Metacaracterul * în paranteză () se comportă Greedy: As Many As Possible (longest match) #=pod $secv = 'accgtgttttacctttaccgtgttttaccttta'; print "\nEXEMPLUL (5)\n"; print "În secvența: $secv\n"; print 'Expresia REGEX: m/(a.c)(.*)(t.t)/g'," determină\n"; while ($secv =~ m/(a.c)(.*)(t.t)/g){ print 'Variabila $& are valoarea ',"$&\n"; print 'Variabilele $1 $2 $3 ',"au valorile: $1 , $2 , $3 \n"; print "Cautarea continuă de la poziția: ", pos($secv),"\n"; } #=cut # Combinația *? în paranteză () se comportă Lazy: As Few As Possible (shortest match) #=pod $secv = 'accgtgttttacctttaccgtgttttaccttta'; print "\nEXEMPLUL (6)\n"; print "În secvența: $secv\n"; print 'Expresia REGEX: m/(a.c)(.*?)(t.t)/g'," determină\n"; while ($secv =~ m/(a.c)(.*?)(t.t)/g){ print 'Variabila $& are valoarea ',"$&\n"; print 'Variabilele $1 $2 $3 ',"au valorile: $1 , $2 , $3 \n"; print "Cautarea continuă de la poziția: ", pos($secv),"\n"; } #=cut # Acest exemplu evidențiază un alt mod de a identifica match-ul mai multor grupuri # chiar dacă numărul acestora nu este antecunoscut. Această situație apare des în cazuri # în care programul primește diverse expresii REGEX pe care urmează să le aplice. În astfel de # situații nu se poate anticipa câte grupuri urmează să conțină o expresie și, prin urmare, # nu se pot exploata variabilele $1...$n. Din această cauză progrmul trebuie să se poată # adapta la un număr variabil de grupuri. # DE AVUT ÎN VEDERE faptul că în situația în care o expresie REGEX are mai multe grupuri # marcate opțional(?), chiar dacă unele nu se vor potrivi, acestea vor introduce în @captures # șiruri vide (''). De ex. dacă sunt trei grupri (a.c)?..(t.t)?..(t.t)? și numai primul este # identificat (match), iar celelalte două nu, atunci @captures se inițializează cu ('acc','',''). # De aceea, exploatarea @captures trebuie făcută cu atenție, de regulă, se parcurge căutând # prezența sau absența șirului vid pentru a identifica grupurile. #=pod $string = 'accgtgtttaccgtttcccacgtttac'; print "\nEXEMPLUL (7)\n"; print "În secvența: $string\n"; print 'Expresia REGEX: m/(a.c)?..(t.t)?..(t.t)?/ determină:',"\n"; my @captures = ($string =~ m/(a.c)?..(t.t)?..(t.t)?/); # m/(a.c).+(t.t).+(t.t)[\w]/ print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print "Grupurile identificate: @captures\n"; print 'Variabila @captures are ',$#captures+1," componente\n"; #=cut # Acest exemplu evidențiază comportamentul variabilei @captures în stuația # în care grupul (a.c) marcat cu + poate avea una sau mai multe apariții. # În această situație nu se poate anticipa de câte ori va fi identificat. De aceea # variabila $1 alocată grupului va păstra configurația doar a ultimului match. # DE AVUT ÎN VEDERE că variabilele $1..$n sunt alocate strict numărului de grupuri # definite în cadrul expresiei REGEX. Faptul că un match poate fi rezultatul unui # grup identificat de mai multe ori ca în exemplul (8), nu conduce la generarea # suplimentară a altor variabile de tipul $n pentru fiecare situație. De aceea $1 # va deține doar ultima configurație agc deși, anterior au existat acc și atc. # Exemplul mai este interesant și din perspectiva implementării instrucțiunii for # folosită în scopul parcurgerii conținutului variabilei @captures. #=pod $secv = 'accatcagcgtgtttaccgtttcccacgtttac'; print "\nEXEMPLUL (8)\n"; print "În secvența: $secv\n"; print 'Capturarea rezultatului /^(a.c)+/ în variabila @captures',"\n"; my @captures = $secv =~ /^(a.c)+/g; print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print 'Variabila $1 ',"are valoarea: $1\n"; print 'Grupurile identificate in variabila @captures sunt: '; print "$_ " for (@captures); print "\n"; #=cut # CODE CAPSULE (?{…}) # PERL REGEX are o caracteristică specială/unică: capacitatea de a permite inserarea # de fragmente de cod care să poată fi executate în timpul evaluării unei expresii. # Sintaxa (?{…}) creează o capsulă pentru introducerea unor instrucțiuni. # Într-o astfel de situație, PERL execută instrucțiunile dintre acolade {…}. # Acest exemplu evidențiază soluționarea unei situații, altfel, imposibl de rezolvat: # posibilitatea de a captura fiecare grup pe măsură ce expresia avansează în # identificarea pattern-ului. # În exemplul (9) expresia /^((a.c)(?{push(@captures,$2);push(@locations,$-[2])}))+/ # este constituită din două grupuri: (a.c) care trebuie identificat de mai multe ori # și (?{push(@captures,$2);push(@locations,$-[2])}) care este o capsulă de cod. Aceasta # exploatează variabila $2 pentru că este alocată chiar acestui grup și prin intermediul # ei se poate ajunge secvențial la pattern-urile identificate prin (a.c). Ca întreaga # expresie să se comporte unitar, cele două grupuri: (a.c) și # (?{push(@captures,$2);push(@locations,$-[2])}) au fost unite în cadrul unor paranteze # suplimentare la care s-a adăugat metacaracterul + pentru multiplicare. # Atenție la variabilele $1..$n, ele sunt alocate, în ordine, în funcție de numărul de # grupuri descrise în expresie. Este important să se aleagă corect variabila alocată # grupului ce conține codul pentru a putea exploata pattern-urile identificate. #=pod $secv = 'accatcagcgtgtttaccgtttcccacgtttac'; print "\nEXEMPLUL (9)\n"; print "În cadrul secvenței: $secv\n"; print 'se poate captura rezultatul secvential al grupului (a.c)+ în variabila @captures',"\n"; print 'si totodată posibilitatea de identifica locatiile acestora în cadrul sirului',"\n"; print 'cu ajutorul expresiei ^((a.c)(?{push(@captures,$2);push(@locations,$-[2])}))+',"\n"; $secv =~ /^((a.c)(?{push(@captures,$2);push(@locations,$-[2])}))+/; print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print 'Variabilele $1 $2 ',"au valorile: $1 , $2 \n"; print 'Grupurile identificate in variabila @captures sunt urmatoarele: '; print "$_ " for (@captures); print "\n"; print 'Locatiile acestor grupuri sunt stocate în variabla @locations: '; print "$_ " for (@locations); print "\n"; #=cut # Acest exemplu scoate în evidență modificatorul x pentru descrierea unei expresii REGEX #=pod $secv = 'aCCgtgttttaccTTTacctgTTTTaccttt'; print "\nEXEMPLUL (10)\n"; print "În cazul secvenței: $secv\n"; print 'Expresia REGEX: m/ (a.c) (.*) (t.t) /xig',"\n"; print 'produce același efect ca expresia: m/ (a.c) (.*) (t.t) /xig',"\n"; print 'Modificatorul /x determină neluarea în considerare a caracterului spațiu',"\n"; print 'atunci când este utilizat în descrierea unei expresii REGEX',"\n"; while ($secv =~ m/ (a.c) (.*) (t.t) /xig){ print 'Variabila $& are valoarea: ',"$&\n"; print 'Variabilele: $1 , $2 , $3 ',"au valorile: $1 , $2 , $3\n"; } #=cut # Acest exemplu scoate în evidență utilitatea funcției pos($sir) # Funcția poate fi folosită numai în combinație cu operatorul =~ REGEX. #=pod $secv = 'accgtgttttacctttccctgtggccg'; print "\nEXEMPLUL (11)\n"; print "În cazul secvenței: $secv\n"; print 'Expresia REGEX: m/cc.tgt/g'," determină:\n"; while ($secv =~ m/cc.tgt/g) { print "A fost identificata secventa $&\n"; print "Pozitia de inceput este: $-[0]\n"; print "Pozitia de sfarsit este: $+[0]\n"; print "Cautarea continua de la pozitia: ", pos($secv),"\n"; } #=cut # Acest exemplu demonstrează funcția reverse() #=pod $secv = "GGGCCTTA"; $rev = reverse($secv); print "\nEXEMPLUL (11)\n"; print "Se consideră secvența de referință:\t$secv\n"; print "Reversul acestei secvențe este:\t\t$rev\n"; $secv =~ tr/ACGT/TGCA/; #transliterație # Cel mai simplu mod de a obține complementul unei secvențe print "Complementul acestei secvențe este:\t$secv\n"; $rev =~ tr/ACGT/TGCA/; #transliterație print "Revers-complementul secventei este:\t$rev\n"; #=cut # Atenție la utilizarea substituției în modul descris mai jos. # Această situație NU conduce la obținerea revers-complementului. # $rev =~ s/G/C/g; # $rev =~ s/C/G/g; # $rev =~ s/A/T/g; # $rev =~ s/T/A/g; # NON-CAPTURING GROUPS # Grupurile care nu permit captura se comportă similar cu cele care permit captura. # Diferența apare în cazul variabilelor care păstrează rezultatul match-ului de grup. # Cele care permit captura păstrează rezultatul în variabilele $1, $2, $3 , ... , # Grupurile care nu permit captura nu păstrează rezultatul grupului, deci, pentru # aceste grupuri nu se alocă variabile speciale care să păstreze rezultatul match-ului. # Din această cauză, indiferent cum este scris șirul, # cu sau fără st, nd, rd, th, se capturează doar partea numerică. # ! ATENȚIE LA COMPORTAMENTUL variabilei @captures în combinație cu modificatorul /g # După cum se poate observa în rezultat, instrucțiunea @captures = ($secv =~ /([0-9]+)(?:st|nd|rd|th)?/g); # se comportă asemănător cu o iterație pentru că modificatorul /g impune efectuarea tuturor match-urilor # posibile cu salvarea tuturor rezultatelor în variabila @captures (array). #=pod $secv = '1st, 2nd, 3rd, 4th'; @captures = (); print "\nEXEMPLUL (12)\n"; print "\În cazul secvenței: $secv\n"; print 'Expresia REGEX: /([0-9]+)(?:st|nd|rd|th)/g'," determină:\n"; @captures = ($secv =~ /([0-9]+)(?:st|nd|rd|th)?/g); print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print 'Grupurile identificate sunt: ',"@captures\n"; #=cut #=pod $secv = '1st, 2nd, 3rd, 4th'; @captures = (); print "\nEXEMPLUL (13)\n"; print "\În cazul secvenței: $secv\n"; print 'Expresia REGEX: /([0-9]+)(st|nd|rd|th)/g'," determină:\n"; @captures = ($secv =~ /([0-9]+)(st|nd|rd|th)?/g); print 'Variabila $& s-a potrivit cu: ',"$&\n"; print 'Variabila $` s-a potrivit cu: ',"$`\n"; print 'Variabila $\' s-a potrivit cu: ',"$'\n"; print 'Grupurile identificate sunt: ',"@captures\n"; #=cut