05. Control Structures and Loops

Λογικοί Έλεγχοι

Με τον όρο "λογικός έλεγχος" εννοούμε οποιαδήποτε συντακτική δομή χρησιμοποιείται για να ελέγξει τη σχέση μεταξύ δύο μεταβλητών. Τέτοιες σχέσεις μπορεί να είναι:

  • αριθμητικές σχέσεις ισότητας/ανισότητας/διαφοράς (α=β, α>β, α>=β, α<=β, α<β ή α "μη ίσο του" β)
  • σχέσεις ισότητας/διαφοράς σε string (x "ταυτίζεται με" y, x "διάφορο του" y)
  • σχέσεις ύπαρξης strings μέσα σε μεγαλύτερα strings.

Aνάλογα με το αν πρόκειται για σύγκριση numeric ή string μεταβλητές οι τελεστές για τις πιο πάνω σχέσεις είναι:

Συγκρίσεις numeric

Οι τελεστές μεταξύ των ελέγχων σε numeric και string είναι διαφορετικοί γι' αυτό θα πρέπει να θυμόμαστε ότι όταν χειριζόμαστε αριθμητικές τιμές τότε ισχύουν οι παρακάτω τελεστές:

  1. Αριθμητική σχέση ισότητας: == . Ο τελεστής είναι το διπλό ίσον καθώς το απλό "=" χρησιμοποιείται για την πράξη της απόδοσης τιμής σε μεταβλητή. Έτσι αν θέλουμε να ελέγξουμε αν δύο αριθμητικές μεταβλητές είναι ίσες τότε θα πρέπει να ελέγξουμε την έκφραση $a == $b. (Περισσότερα για το πώς γίνεται αυτός ο έλεγχος παρακάτω.)
  2. Αριθμητική σχέση ανισότητας: !=. Ο τελεστής είναι η "άρνηση ισότητας" που εισάγεται με το ! ακολουθούμενο από το =. Το σύμβολο του θαυμαστικού είναι γενικώς σύμβολο αναίρεσης.
  3. Αριθμητικές σχέσεις μεγαλύτερου, μικρότερου: >, <, >=, <= . Χρησιμοποιούνται τα γνωστά σύμβολα του μεγαλύτερου, μικρότερου. Προσοχή στα "μεγαλύτερο/μικρότερο ή ίσο" η σειρά των συμβόλων είναι όπως την εκφέρουμε στη φράση.
  4. Ο τελεστής <=> χρησιμοποιείται για να εξεταστούν όλες οι συνθήκες μεγαλύτερου, ίσου, μικρότερου ταυτόχρονα. Χρησιμοποιείται σε παράσταση ($a <=> $b) η οποία παίρνει αυτομάτως τις τιμές: 1 αν $a>$b, 0 αν $a=$b και -1 αν $a<$b. Για παράδειγμα:

#! /usr/bin/perl use warnings;

$a=10;

$b=12;

$x=($a <=> $b);

print $x,"\n"; # will print -1

Συγκρίσεις σε string

ενώ όταν χειριζόμαστε string ισχύουν οι εξής:

  1. Ισότητα strings: eq. Όταν μιλάμε για "ισότητα strings" εννοούμε πως δύο σειρές χαρακτήρων ταυτίζονται είναι δηλαδή πανομοιότυπες σε ό,τι αφορά το μήκος και τη διαδοχή των χαρακτήρων. Ο έλεγχος της ταυτότητας των string $x και $y θα γίνει μέσω της έκφρασης ($x eq $y).
  2. Mη-ισότητα: ne. Ως μη-ισότητα ορίζεται οποιαδήποτε κατάσταση δεν είναι ταύτιση, κάτι που σημαίνει πως αρκεί διαφορά ενός χαρακτήρα (πολλές φορές και "κρυφού" όπως π.χ. η ύπαρξη του τελικού "\n") για να ισχύει μη ισότητα. Το ne είναι τα αρχικά "non equal" σε αντίθεση με τo eq ("equal").
  3. Έλεγχοι strings σε αλφαβητική σειρά. Η αντίστοιχη σύγκριση των strings με τις σχέσεις μεγαλύτερου, μικρότερου για τις αριθμητικές μεταβλητές είναι η σχέση προτεραιότητας κατ' αλφαβητική σειρά. Έτσι αν ένα string είναι πριν από ένα άλλο σε αλφαβητική σειρά θεωρούμε πως είναι "μεγαλύτερο" και η σχέση συμβολίζεται με το gt (greater than). Αντίστοιχα η υστέρηση σε αλφαβητική σειρά αντιστοιχεί σε "μικρότερο", lt (less than) ενώ αντίστοιχες με τις >= και <= είναι οι ge (greater or equal) και le (less or equal). Aν για παράδειγμα θέλουμε να δουμε ποιο από δύο strings $x, $y είναι πριν από το άλλο σε μια αλφαβητική κατάταξη θα ελέγξουμε την παράσταση ($x gt $y) ή αντιστρόφως ($x lt $y).
  4. O ειδικός τελεστής cmp έχει την ίδια λειτουργία με το <=> για σχέσεις σε strings. Έτσι η παράσταση ($x cmp $y) δίνει 1,0,-1 ανάλογα με το αν το $x προηγείται, είναι στην ίδια θέση ή έπεται του $y σε αλφαβητική σειρά.

#! /usr/bin/perl use warnings;

$a="AGCT";

$b="GCTA";

print $a cmp $b,"\n"; # will print 1

Συνοπτικά

Συνοπτικά τα είδη των τελεστών σύγκρισης για αριθμητικές παραστάσεις και για παραστάσεις χαρακτήρων φαίνονται στον παρακάτω πίνακα. Υπενθυμίζεται πως σε όλες τις περιπτώσεις για τις συγκρίσεις χαρακτήρων οι σχέσεις μεγαλύτερου/μικρότερου έχουν να κάνουν με την αλφαβητική σειρά των χαρακτήρων.

Αναζήτηση σειρών χαρακτήρων σε strings

Η αναζήτηση τμημάτων χαρακτήρων σε μεγαλύτερες σειρές χαρακτήρων είναι μια από τις πιο βασικές διαδικασίες. Γίνεται με διάφορους τρόπους σε ό,τι αφορά το αναζητούμενο κομμάτι αλλά η βασική ιδέα είναι η σύνταξη της εντολής:

>Δες αν το $line είναι υποσύνολο (υπάρχει μέσα στο) $string

H κωδικοποίησή της γίνεται με τον τελεστή =~/.../ και τη χρήση ενός λογικού ελέγχου. Για παράδειγμα αν θέλουμε να ελέγξουμε την ύπαρξη του $line εντός του $string. Θα πρέπει να γράψουμε:

if ($string =~/$line/) ...

Περισσότερα για τη δομή if θα δούμε παρακάτω και πιο εκλεπτυσμένες αναζητήσεις θα δούμε στο Κεφάλαιο των Κανονικών Εκφράσεων.

Μια πολύ χρήσιμη εντολή που συνδυάζει την αναζήτηση με την απαρίθμηση είναι μέσω της εντολής αντικατάστασης σε string με ταυτόχρονη απόδοση σε μεταβλητή.

Έστω ότι θέλουμε να μετρήσουμε πόσες φορές το $line βρίσκεται εντός του $string. Δεν έχουμε παρά να κάνουμε μια συνολική αντικατάσταση του $line με τον εαυτό του (για να μην αλλάξει το $string) και ταυτόχρονα να αποδώσουμε αυτή την πράξη σε μια βαθμωτή μεταβλητή:

$times=($string =~ s/$line/$line/g);

print $times,"\n";

To $times τώρα περιέχει τον αριθμό των φορών που έγινε η αντικατάσταση (προσοχή στο flag /g) και άρα τον αριθμό των εμφανίσεων του $line στο $string. Γενικότερα η απόδοση μιας πράξης σε μεταβλητή στην Perl είναι συνήθως πράξη απαρίθμησης, αποδίδει δηλαδή τον αριθμό των πράξεων που πραγματοποιήθηκαν.

Δομές Ελέγχου

if/elsif/else

Ως τώρα έχουμε δει μόνο με ποιον τρόπο συντάσσουμε τις εκφράσεις με τις οποίες διενεργούνται οι λογικοί έλεγχοι. Στην Perl όπως και στις περισσότερες γλώσσες προγραμματισμού η βασική δομή ελέγχου συντάσσεται με την εντολή if.

if (control statement) {actions}

Όπου μέσα στην παρένθεση (statement) μπαίνει η έκφραση την οποίαν θέλουμε να ελέγξουμε ενώ μέσα σε άγκιστρα "{}" ακολουθούν οι εντολές οι οποίες εκτελούνται ΜΟΝΟ σε περίπτωση που η έκφραση είναι αληθής. Για παράδειγμα

$a=1;

if ($a>0) {

print $a,"\n";

}

Οι παραπάνω εντολές τυπώνουν την τιμή 1 στην οθόνη ενώ οι παρακάτω:

$a=1;

if ($a<=0) {

print $a,"\n";

}

δεν τυπώνουν τίποτα καθώς στη συγκεκριμένη περίπτωση η συνθήκη μέσα στην παρένθεση δεν ικανοποιείται.

Για να αποφεύγονται αμφιβολίες που έχουν να κάνουν με τη σωστή εκτέλεση εντολών είναι καλό πάντα να συντάσσουμε τις εντολές if με τρόπο τέτοιο ώστε να υπάρχει αποδιδόμενη "ενέργεια" για όλα τα ενδεχόμενα του ελέγχου (αληθής/ψευδής). Αυτό μπορεί να γίνει ως εξής:

$a=1;

if ($a>0) {

print $a,"\n";

}

else {

print "$a is not greater than 0\n";

}

με την δομή δηλαδή:

if (control statement) {actions}

else {actions}

Στην περίπτωση που θέλουμε να ελέγξουμε περισσότερα από 2 ενδεχόμενα αυτό μπορεί να γίνει με την εντολή elsif ως εξής:

if (control 1 statement) {actions}

elsif (control 2) {actions}

elsif (control 3){actions}

...

else {actions}

Στην τελευταία περίπτωση εξετάζουμε μια σειρά από αλληλοαποκλειόμενα ενδεχόμενα με διαδοχικές εντολές if (η elsif είναι στην ουσία if δεδομένου του αποκλεισμού κάποιου άλλου ελέγχου) και στο τέλος δηλώνουμε τις ενέργειες που πρέπει να εκτελεστούν για την περίπτωση που κανένα από τα ενδεχόμενα αυτά δεν επαληθεύεται.

unless

H εντολή unless είναι απολύτως συμπληρωματική της if με την ακριβώς αντίθετη έννοια. Έτσι μπορεί να χρησιμοποιηθεί αντί της if για αντιστροφή του ζητουμένου. Οι εντολές π.χ.:

if ($a>0) {...}

unless ($a <= 0) {...}

Είναι απολύτως ισοδύναμες. Η εντολή unless συνδυάζεται στην περίπτωση άλλων ενδεχομένων με elsif εντολές καθώς δεν υπάρχει εντολή που να κωδικοποιείται ως "elseunless".

Συνδυασμός ελέγχων. Τελεστές Boole. (Βοοlean operators)

Τι συμβαίνει σε περιπτώσεις που θέλουμε να ικανοποιούνται περισσότερες από μια συνθήκες ταυτόχρονα, όταν θέλουμε να διακρίνουμε μεταξύ δύο διαφορετικών περιπτώσεων και γενικά όταν θέλουμε να συνδυάσουμε ελέγχους; Σε όλες τις παραπάνω περιπτώσεις χρησιμοποιούμε τους ειδικούς τελεστές της Άλγεβρας Boole (Boolean operators) για να κωδικοποιήσουμε ακριβώς τον τύπο του συνδυασμού που επιθυμούμε. Οι τελεστές αυτοί αντιστοιχούν στις τρεις βασικές λογικές πράξεις με τις οποίες μπορούμε να συνδυάσουμε δύο ελέγχους Α, Β:

  1. Α ΚΑΙ Β (Τελεστές "and", "&&")
  2. Α Η Β (Τελεστές "or", "ΙΙ")
  3. Α ΚΑΙ ΟΧΙ Β (Τελεστές "and not", "!")

Έτσι για παράδειγμα χρησιμοποιούμε τον τελεστή "and" όταν επιθυμούμε δύο ή περισσότεροι έλεγχοι να ισχύουν ταυτόχρονα:

$a=5;

if ( ($a>0) and ($a<=10) ) {

print $a,"\n";

}

else {

print "no success\n";

}

Aπολύτως ανάλογη είναι η παραπάνω σειρά των εντολών με τη χρήση του "&&" στη θέση του "and". Η διαφορά των "&&", "||" από τα "and", "or" είναι μόνο σε επίπεδο προτεραιότητας (precedence) αλλά για τις ανάγκες του μαθήματός μας αυτό δεν θα μας απασχολήσει.

Με τον ίδιο ακριβώς τρόπο ελέγχουμε την διάζευξη δύο ή περισσότερων ελέγχων με τη χρήση του "οr":

$a=5;

if (($a==5) or ($a==2) or ($a==3)) {

print $a,"\n";

}

else {

print "no success\n";

}

Προσοχή στη χρήση των παρενθέσεων στην εντολή if εφόσον εξετάζονται περισσότεροι από ένας έλεγχοι. Η κάθε παράσταση θα πρέπει να μπαίνει σε ξεχωριστή παρένθεση.

Επαναληπτικές Διαδικασίες

Οι επαναληπτικές διαδικασίες ή "βρόχοι επανάληψης" (loop structures) είναι βασικά στοιχεία όλων των γλωσσών προγραμματισμού. Μας δίνουν τη δυνατότητα να επαναλάβουμε μια σειρά διαδικασιών και εντολών κατά βούληση έτσι ώστε να επιτύχουμε:

  • Τη διενέργεια μιας σειράς υπολογισμών
  • Τη διενέργεια μιας σειράς ελέγχων
  • Την απαρίθμηση στοιχείων
  • Συνδυασμούς των παραπάνω

Oι δομές επανάληψης μπορούν να εισαχθούν αυτόνομα ή να αναφέρονται σε κάποια δομή δεδομένων όπως ένας πίνακας. Μπορούμε δηλαδή να επαναλάβουμε μια διαδικασία αναφερόμενοι στα στοιχεία ενός πίνακα ή και χωρίς να αναφερόμαστε σε αυτά. Παρακάτω θα δούμε πιο αναλυτικά πως γίνεται αυτό εξετάζοντας τις βασικές εντολές με τις οποίες εισάγονται οι δομές επανάληψης όπως είναι οι εντολές for, foreach και while/until.

for/foreach

Οι εντολές for, foreach χρησιμοποιούνται κυρίως για να εισάγουμε επαναληπτικές διαδικασίες πάνω σε στοιχεία πινάκων (διατεταγμένων ή μη). H εντολή for μπορεί να εισαχθεί με δύο τρόπους. O ένας χρησιμοποιεί μια βοηθητική μεταβλητή με τον εξής τρόπο:

@spring = ("March", "April", "May");

for $month (@spring) {

print $month, "\n";

}

Στην πιο πάνω σειρά εντολών η μεταβλητή $month εισάγεται μέσα στην εντολή for με σκοπό να τη χρησιμοποιήσει για να "διατρέξει" όλον τον πίνακα. Η λειτουργία των παραπάνω εντολών είναι η επανάληψη της εντολής εκτύπωσης print για καθένα από τα στοιχεία του πίνακα @spring. Απολύτως ανάλογη είναι η διαδικασία με τη χρήση της εντολής foreach

foreach $month (@spring) {

print $month,”\n";

}

Πρακτικά σε αυτό το επίπεδο, δεν υπάρχει καμιά διαφορά μεταξύ των δύο. Μια βασική διαφορά τους είναι η δυνατότητα χρήσης του for με "απαριθμητικό" τρόπο. Αυτός συνίσταται στην πιο αναλυτική αναγραφή του βρόχου επανάληψης που μας επιτρέπει όχι μόνο να εφαρμόσουμε μια επαναληπτική διαδικασία σε όλα τα στοιχεία ενός πίνακα αλλά και σε ένα υποσυνολό τους, καθώς και με διαφορετική σειρά ή με περιοδικό τρόπο. Στα παρακάτω παραδείγματα έχουμε έναν πίνακα @array με 100 στοιχεία. Μπορούμε με την εντολή for να τυπώσουμε όλα τα στοιχεία του στη σειρά:

for ($i=0; $i<=99; $i++) {

print $array[$i],"\n";

}

Σε αυτήν την περίπτωση η βοηθητική μεταβλητή $i λειτουργεί ως μετρητής (counter) ο οποίος παίρνει τιμές από την πρώτη ($i=0) ως την τελευταία ($i<=99) αυξανόμενος κάθε φορά κατά 1 ($i++). Tα 100 στοιχεία του @array έτσι εξαντλούνται με τη σειρά από το πρώτο έως το τελευταίο. (Απολύτως ισοδύναμη πρώτη γραμμή θα ήταν η for ($i=0; $i<=99; $i+=1) {)

Έστω τώρα ότι θα θέλαμε να τυπώσουμε (ή να κάνουμε οποιαδήποτε άλλη πράξη) στα στοιχεία 10 έως 20 μόνο του @array. Κάτι τέτοιο δεν μπορεί να γίνει με την foreach αλλά με μια for σαν την παρακάτω:

for ($i=9; $i<=19; $i++) {

print $array[$i],"\n";

}

Ενώ στην περίπτωση που θα θέλαμε να αντιστρέψουμε τη διαδοχή των στοιχείων θα πρέπει απλώς να αντιστρέψουμε την σειρά με την οποία δίνονται οι τιμές και η "προσαύξηση" (incrementation) να γίνει "απομείωση" (decrementation):

for ($i=99; $i>=0; $i--) {

print $array[$i],"\n";

}

Προσοχή στο $i>=0 και το $i-- σε αυτήν την περίπτωση.

Τέλος αν επιθυμούμε μια διαδικασία να γίνει σε σταθερά "άλματα" αντί η αύξηση ή μείωση να γίνεται κατά 1 μπορούμε απλώς να αλλάξουμε το "βήμα" της διαδικασίας:

for ($i=99; $i>=0; $i-=3) {

print $array[$i],"\n";

}

Η τελευταία αυτή σειρά εντολών ξεκινά τυπώνοντας το τελευταίο στοιχείο του πίνακα @array και καταλήγει στο κοντινότερο του πρώτου "πηδώντας" ανα τρία στοιχεία (100ο, 97ο, 94ο ...κ.ο.κ.).

while/until

Oι εντολές while/until εισάγουν δομές επανάληψης με τρόπο διαφορετικό από της for/foreach. Συγκεκριμένα, εισάγουν ταυτόχρονα μια δομή επανάληψης και έναν λογικό έλεγχο που εμπεριέχεται στην εντολή. Για παράδειγμα, στις εντολές:

$a=10;

while ($a>=0){

print $a;

$a--;

}

H μεταβλητή $a ξεκινά με την τιμή 10 η οποία τυπώνεται μέσα σε έναν "βρόχο" while ενώ ταυτόχρονα σε κάθε "κύκλο" του βρόχου απομειώνεται κατά 1. Όταν η $a φτάσει να είναι μικρότερη του 0 τότε ο βρόχος τερματίζεται καθώς η παράσταση $a>=0 δεν είναι πλέον αληθής. Απολύτως ανάλογη είναι η παραπάνω διαδικασία με τη χρήση του until.

$a=10;

until ($a<0){

print $a;

$a--;

}

Mε τρόπο ανάλογο της σχέσης if/unless οι while/until μπορούν να κωδικοποιήσουν την ίδια ακριβώς διαδοχή εντολών.

Η βασικότερη χρήση της while σε προγράμματα Perl ωστόσο είναι στην κωδικοποίηση της ανάγνωσης αρχείων ανά γραμμή μέσω της εντολής:

while (<FILE>) {

commands;

...

}

Στην παραπάνω σύνταξη, στο πεδίο FILE εισάγεται το εσωτερικό όνομα ενός αρχείου, ένα FILEHANDLE δηλαδή (βλ. κεφάλαιο Input/Output). Η while σε αυτήν την περίπτωση ελέγχει σε κάθε επανάληψη αν η γραμμή του αρχείου είναι "γεμάτη" περιέχει δηλαδή στοιχεία. Με αυτόν τον τρόπο, ο βρόχος επανάληψης διαβάζει όλο το αρχείο γραμμή, προς γραμμή και μας δίνει τη δυνατότητα να εκτελέσουμε μια σειρά από εντολές για κάθεμία από αυτές. Ένα απλό παράδειγμα είναι το παρακάτω. Φανταστείτε ότι το FILEHANDLE SEQ περιέχει μια αλληλουχία σε fasta format. Σκεφτείτε πως με τη χρήση του while θα μπορέσετε να διαβάσετε ολόκληρη την αλληλουχία σε μια βαθμωτή μεταβλητή.

open SEQ, "<human.fa";

while (<SEQ>){

chomp;

$sequence.=$_;

}

print $sequence;

next/last/redo

O χειρισμός των επαναληπτικών διαδικασιών χρειάζεται ιδιαίτερη προσοχή. Ειδικά σε επίπεδο αρχαρίων υπάρχει συχνά ο κίνδυνος "ατέρμονων" βρόχων που δεν τερματίζουν ποτέ, ή βρόχων που χρειάζονται πολύ λιγότερα βήματα απ' όσα κωδικοποιούνται και κατά συνέπεια εκτελούν περιττές εντολές με κόστος σε μνήμη και υπολογιστική ισχύ. Πέρα από την σωστή και προσεκτική δόμηση των βρόχων, υπάρχει και μια σειρά από εντολές που επιτρέπουν τη διακοπή τους, τον πρόωρο τερματισμό τους ή και την ελεγχόμενη εφαρμογή τους σε περισσότερα από ένα βήματα. Αυτές είναι οι εντολές next, last και redo.

H εντολή next εισάγεται στην περίπτωση που επιθυμούμε την διακοπή ενός βρόχου και την συνέχισή του στο επόμενο βήμα χωρίς την ολοκλήρωση των υπόλοιπων εντολών.

$a=10; while ($a>=0) { if ($a==5) {

$a--; next; } print $a,"\n"; $a--; }

Στο παραπάνω παράδειγμα θα τυπωθούν όλες οι τιμές από το 10 ως το 0 εκτός από την 5 γιατί στο σημείο αυτό ζητάμε να γίνει "άλμα εντολών".

Η εντολή redo διακόπτει τη ροή των εντολών αλλά επαναλαμβάνει τη διαδικασία από το σημείο που διακόπηκε χωρίς να περνά στο επόμενο βήμα.

$a=10;

while ($a>=0) {

if ($a==$b) {

$b=100;

redo;

}

print $a,"\n";

$a--;

}

Στο πιο πάνω παράδειγμα, η διαδικασία της απομείωσης του $a συνεχίζεται εκτός αν το $a βρεθεί ίσο με το $b. Στην περίπτωση αυτή το $b θα γίνει ίσο με το 100 (ώστε να μην συμπίπτει με το $a) καιη διαδικασία θα ξαναγυρίσει στην τιμή που είχε το $a όταν βρέθηκε ίσο με το $b.

Η εντολή last τέλος επιτρέπει την ολοκλήρωση των εντολών που υπολείπονται για το δεδομένο στοιχείο/βήμα της επανάληψης αλλά τερματίζει τον βρόχο αμέσως μετά από αυτές, μην επιτρέποντας στο βρόχο να συνεχίσει στα υπόλοιπα στοιχεία.

$a=10;

while ($a<=0) {

if ($a==$b) {

last;

}

print $a,"\n";

$a--;

}

Στις παραπάνω εντολές, η απομείωση του $a θα γίνει κανονικά από το 10 ως το 0 εκτός αν το $a βρεθεί σε κάποιο σημείο ίσο με το $b οπότε και θα τυπωθεί, θα απομειωθεί κανονικά και o βρόχος θα τερματίσει.

Aνάγνωση δεδομένων από αρχείο με επαναληπτική διαδικασία

Μέχρι τώρα είχαμε δει πώς διαβάζουμε δεδομένα από τη γραμμή εντολών και πώς κάνουμε το ίδιο από ένα αρχείο με επαναληπτικό τρόπο. Στο Κεφάλαιο που εξετάζαμε την ανάγνωση και εγγραφή σε αρχείο είχαμε δει την παρακάτω δομή με τη χρήση της εντολής while () {}. Η συγκεκριμένη εντολή δεν προϋποθέτει τη γνώση του μεγέθους του αρχείου και απλώς ζητά από το πρόγραμμα να διαβάζει γραμμή-γραμμή το αρχείο SEQ μέχρι να φτάσει στο τέλος του. Η σειρά των εντολών:

open SEQ, “<sequence.fa”;

while($a=<SEQ>){ print $a; }

Ουσιαστικά θα ξανατυπώσει το σύνολο του αρχείου SEQ στην οθόνη, γραμμή-γραμμή. Για την ακρίβεια θα τυπώνει την κάθε γραμμή μαζί με τον τελικό "\n" χαρακτήρα που κωδικοποιείται από το "Enter" εντός του αρχείου και γι' αυτό τον λόγο δεν χρειάζεται να τον ενσωματώσουμε στην εντολή print.

Δεδομένου ότι τώρα έχουμε καλύψει τη λογική της while μπορούμε να δούμε μια γενίκευση των παραπάνω εντολών που έχουν ώς εξής:

open SEQ, “<sequence.fa”;

while(<SEQ>){

print $_; }

Στο παραπάνω παράδειγμα υπάρχουν δύο βασικές αλλαγές σε σχέση με το προηγούμενο. Πρώτον η ανάγνωση του αρχείου γίνεται απευθείας χωρίς την απόδοση μεταβλητής με την εντολή:

while(<SEQ>)

Δεύτερον δεν ορίζεται πουθενά κάποια μεταβλητή παρά ζητάμε να τυπωθεί μια περίεργη μεταβλητή που συμβολίζεται με $_. H $_ είναι μια εξ ορισμού (default) μεταβλητή της Perl που αντιστοιχεί στην τελευταία αναγνωσμένη μεταβλητή μέσα σε έναν βρόχο while. Με αυτόν τον τρόπο δεν χρειάζεται να διαβάσουμε το αρχείο μέσα σε μια μεταβλητή καθώς αυτό γίνεται αυτόματα μέσω της while σε μια μεταβλητή που ονομάζεται $_.

Δοκιμάστε μόνοι σας:

Προσπαθήστε να γράψετε ένα πρόγραμμα που θα κάνει τα παρακάτω:

1. Θα ανοίγει για ανάγνωση τα δύο αρχεία human.fa, sites.tab που θα βρείτε συνημμένα στο τέλος της σελίδας.

2. Θα διαβάζει την αλληλουχία που βρίσκεται στο human.fa σε μια βαθμωτή μεταβλητή (scalar)

3. Θα διαβάζει τα ολιγονουκλεοτίδια που βρίσκονται στο sites.tab σε μια λίστα (array)

4. Θα αναζητεί καθένα από τα ολιγονουκλεοτίδια του sites.tab στην αλληλουχία του human.fa ανεξαρτήτως τυποποίησης (πεζά/κεφαλαία) και θα αναφέρει:

α. Την ύπαρξή τους ή μη

β. Το πλήθος των φορών που απαντώνται

γ. (Προαιρετικά) τη θέση τους μέσα στην αλληλουχία (σε αριθμό βάσεων από την αρχή της)