Μαθήματα Perl (Μέρος 1): Μεταβλητές και operators

dimitris | Παρ, 09/05/2008 - 09:21 | 15'

Σε αυτό το πρώτο ...επεισόδιο, εξηγούμε τα βασικά στοιχεία της γλώσσας Perl με παραδείγματα...

Οι scripting γλώσσες είναι δημοφιλείς επειδή, με μικρό κόστος απόδοσης, μας απαλλάσουν από βαρετές δουλειές όπως ορισμούς μεταβλητών, καταμερισμό μνήμης, κλπ. Η Perl (Practical Extraction and Report Language) εφευρέθηκε στα τέλη της δεκαετίας του '80 και είχε σχεδιαστεί για να διαχειρίζεται εύκολα τεράστια ποσά κειμένου. Αν και δεν είναι η δημοφιλέστερη γλώσσα προγραμματισμού σήμερα, παραμένει και είναι μια αναντικατάστατη λύση για πολλές εργασίες.

Η Perl θεωρείται μάλιστα ως η επίσημη "κολλητική ταινία" του διαδικτύου λόγο της δυνατότητας της να επικοινωνεί με έναν μεγάλο αριθμό διαφορετικών συστημάτων και πρωτοκόλλων και την ευελιξία της στο να χειρίζεται τεράστια ποσά ποικιλόμορφων δεδομένων με ευκολία μέσω των module επεκτάσεων και της λεπτομερής τεκμηρίωσης που προσφέρει. Εάν θέλετε να μάθετε ένα τέτοιο παράδειγμα για το πώς η Perl "έσωσε" το Human Genome Project διαβάστε όλη την ιστορία στο http://bioperl.org/GetStarted/tpj_ls_bio.html.

Δεν χρειάζεται να είστε διαχειριστής συστήματος ή προγραμματιστής για να ωφεληθείτε από αυτή την γλώσσα. H Perl μπορεί να σας βοηθήσει στην γρήγορη επεξεργασία ενός κείμενου ή ακόμα και μιας εικόνας. Δεν έχει καν σημασία εάν τα αρχεία που θέλετε να επεξεργαστείτε βρίσκονται τοπικά ή κάπου στο δίκτυο - η Perl με τις κατάλληλες επεκτάσεις τα διαχειρίζεται και τα δύο εξίσου "διάφανα".

Μεταβλητές

Το πρώτο πράγμα που θα σας κάνει εντύπωση στο μάτι με το που θα κοιτάξετε Perl κώδικα είναι πως οι μεταβλητές έχουν ένα μη-αλφαβητικό πρόθεμα. Αυτό για ορισμένους φαίνεται πως γεμίζει την οθόνη με δυσανάγνωστα σύμβολα. Ωστόσο τα σύμβολα αυτά είναι χρήσιμα διότι υποδηλώνουν άμεσα την εσωτερική δομή της αντίστοιχης μεταβλητής καθώς και στο τι μπορείτε να κάνετε με αυτή. Ορίστε ένα παράδειγμα:

$NAME = 'Johnny';
$AGE = 33;
@BOOK= ('Introduction','First Chapter','Second Chapter');
%STAR_WARS_FAMILY = ('Father', 'Anakin', 'Mother', 'Padme', 'Male Twin', 'Luke', 'Female Twin', 'Leia');

Οι πρώτες δύο μεταβλητές ονομάζονται scalar. Τα scalar στην Perl έχουν την δυνατότητα να κρατούν ένα μοναδικό κομμάτι πληροφορίας όπως ένα string, έναν ακέραιο ή ένα reference. Τα ονόματα τους ξεκινούν με το σήμα του δολαρίου. Τα string scalars ξεχωρίζουν ανάλογα με το αν έχουν μονά, διπλά ή ανεστραμμένα εισαγωγικά ενώ οι αριθμοί χρησιμοποιούνται ως έχουν:

$Α = 'Hello';
$B = '$A Johnny!';
$C = "$A Johnny!";
$D = `ls /usr/bin`;

Σε αυτό το παράδειγμα, το $Β θα περιέχει μόνο τους ακριβείς χαρακτήρες που γράψατε μέσα του, το $C (χάρης των διπλών εισαγωγικών) ισούται με "Hello Johnny!" ενώ το $D επειδή χρησιμοποιεί ανεστραμμένα εισαγωγικά, θα περιέχει ολόκληρο το αποτέλεσμα της εντολής ls /usr/bin/, όπως εάν το γράφατε στην γραμμή εντολών.

Τα σε σειρά αριθμημένα scalars λέγονται arrays και σημειώνονται με ένα αρχικό @. Είναι χρήσιμα για την αποθήκευση πραγμάτων κατά αριθμητική σειρά. Ένα στοιχείο του array υποδεικνύετε με ένα $ πρόθεμα, το όνομα του array καθώς και τον δείκτη του (ξεκινώντας από το 0) σε αγκύλες. Οπότε στο παραπάνω παράδειγμα, το περιεχόμενο του δεύτερου στοιχείου του @ΒΟΟΚ - δηλαδή το $BOOK[1] - θα είναι το First Chapter.

Τα associative arrays, ή hashes για ευκολία, είναι η τελευταία κεντρική κατηγορία των Perl μεταβλητών. Ένα hash είναι μια ομάδα από scalars ή οποία παρέχει ευρετήριο για τα δεδομένα της, όχι μέσω αριθμών αλλά μέσω κλειδιών τα οποία εκφράζουν το νόημα της κάθε τιμής μέσα στο hash. Με λίγα λόγια, η Perl εγγενώς μας επιτρέπει να πούμε πως το $STAR_WARS_FAMILY{'Father'} είναι το Anakin, χωρίς παραπάνω σύνταξη ή εντολές. Κάθε κλειδί ή τιμή ενός hash, μπορούν να είναι ένα διαφορετικό τύπου scalar από τα υπόλοιπα. Είναι εύκολο λοιπόν να καταλάβει κάποιος γιατί και το μικρότερο Perl script είναι γεμάτο από $, @ και # χαρακτήρες. Μπορείτε όμως να δημιουργήσετε αρκετά πολύπλοκες δομές δεδομένων στην στιγμή και δίνοντας λίγο προσοχή στην ονομασία των στοιχείων τους, θα μπορείτε να τα θυμόσαστε εύκολα.

Το γεγονός του ότι μπορείτε να 'εμφωλιάσετε' arrays και hashes κατά βούληση, σας δίνει αρκετή δύναμη αν και είναι κάπως επικίνδυνο. Δείτε το παρακάτω παράδειγμα:

%STAR_WARS_FAMILY= (
	'Father', {'Name','Anakin',
	               'Height (cm)', 210,
                        'jobs',['Slave','Podracer pilot', 'Jedi Knight.', 'Darth Vader']},
         'Mother', {} # παρόμοια στοιχεία εδώ
          );
print "$STAR_WARS_FAMILY{'Father'}{'jobs'}[2]\n";

Αυτό είναι ένα hash του οποίου το πρώτο στοιχείο είναι ένα άλλο hash που περιέχει τα στοιχεία Name, Height και jobs. Το jobs στην πραγματικότητα είναι ένα array. Δώστε ειδική προσοχή στην χρήση των αγκύλων και των άγκυστρων για τον διαχωρισμό μεταξύ των hashes και των arrays αντίστοιχα. Το τελικό αποτέλεσμα όλου αυτού του ορισμού είναι πως η print εντολή στο τέλος θα δώσει για αποτέλεσμα το Jedi Knight.

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

print if some_condition_is_true

Εδώ εκτυπώνουμε μόνο εαν έχει ικανοποιηθεί μια συγκεκριμένη συνθήκη. Το πρόβλημα όμως είναι πως δεν ξεκαθαρίζετε τι να εκτυπώθει ή ποια μεταβλητή χρησιμοποιείτε. Στην Perl, όταν συμβεί κάτι τέτοιο, ο διερμηνέας χρησιμοποιεί την τρέχον τιμή της default μεταβλητής η οποία μπορεί να αγνοηθεί ή να καλείται με το $_ σύμβολο.

Αυτό το default σύμβολο, πιθανότατα να είναι το αποτέλεσμα μιας προηγούμενης διεργασίας ή η τρέχον μεταβλητή του βρόγχου που βρισκόσαστε. Εάν το θυμόσαστε αυτό, αρκετός Perl κώδικας θα αρχίζει να γίνεται περισσότερο κατανοητός.

Operators

Η Perl έχει πολλούς operators. Ορισμένοι από αυτούς μπορούν να εφαρμοστούν σε μία μόνο κατηγορία μεταβλητών, είτε scalar, array ή hash ενώ άλλοι μπορούν να αναλάβουν διαφορετικό νόημα και λειτουργία αναλόγως από την μεταβλητή στην οποία εφαρμόζονται. Καθώς υπάρχει περιορισμένος χώρος, θα εξεταστεί μόνο ένα μικρό υποσύνολο αυτών των περιπτώσεων. Οι βασικοί αριθμητικοί operators είναι παρόμοιοι με αυτοί που υπάρχουν στην γλώσσα C:

$A = 10 * 7.5 - 16;
$B = $A % 4; #division modulo 4

Όπως οι αριθμοί έτσι και οι αλφαβητικές τιμές μπορούν να αυτό-αυξηθούν:

$A = 4;
$B = 'ab';
$A++; # τώρα το $Α ισούται με 5
$Β++; # τώρα το $Β ισούται με 'ac' !!!

Μπορείτε επίσης να συνδέσετε μεταξύ τους strings, μία ή και περισσότερες φορές με αυτόν τον τρόπο:

$FIRST_NAME = "Luke";
$LAST_NAME = "Skywalker";
$COMPLETE_NAME = $FIRST_NAME . " " . $LAST_NAME;
$REPEATED_NAME = $FIRST_NAME x 3;

Το $COMPLETE_NAME πλέον ισούται με Luke Skywalker ενώ το $REPEATED_NAME με LukeLukeLuke.

Είναι επίσης πιθανό να συγκρίνετε scalars με διαφορετικούς τρόπους. Για παράδειγμα:

$A < $B; # είναι ο αριθμός $A μεγαλύτερος από τον αριθμό $Β ;
$A lt $B; # είναι το string $A σε θέση πρώτο από το string $B  ;
$Α <=> $Β; # ποιος αριθμός έρχεται πρώτος, ο $A ή ο $Β   ;

Ορισμένες συγκρίσεις έχουν νόημα μόνο όταν και οι δύο μεταβλητές ή strings είναι αριθμοί. Στην περίπτωση αυτή, η δήλωση ' Αυτό το string έρχεται πριν από αυτό', πρέπει να χρησιμοποιηθεί σε ταξινόμηση κατά αλφαβητική παρά κατά αριθμητική σειρά. Ακόμα και εάν τα δύο string περιείχαν μόνο αριθμούς, η χρήση ενός σχετικού με strings operator θα είχε ως αποτέλεσμα μια αλφαριθμητική σύγκριση.

Για να τα δείτε όλα αυτά εν δράσει, πληκτρολογήστε την επόμενη εντολή κατευθείαν από το κέλυφος και σημειώστε ποιες από τις δύο συγκρίσεις είναι αληθής,

perl   -e 'if ("dude" lt "hello") {print "dude!\n";} if ("dude" < "hello") {print "Hello!\n";"}'

Όπως θα δείτε, μόνο ο πρώτος έλεγχος επιτυγχάνεται. Ο operator του συμφωνεί με τα δεδομένα που εφαρμόζεται καθώς ο όλος έλεγχος σημαίνει 'Έρχεται αυτό το string πρώτο πριν από το άλλο κατά αλφαβητική σειρά;". Στον δεύτερο έλεγχο χρησιμοποιώντας τον < operator αντί του lt ζητήσατε από την Perl να ελέγξει εάν ο "αριθμός" dude είναι μικρότερος από τον "αριθμό" hello. Κάτι το οποίο είναι εντελώς χαζό φυσικά με απρόβλεπτα αποτελέσματα.

Μια ιδιοσυγκρασία της Perl που πρέπει να προσέχετε είναι το ότι μετατρέπει αυτόματα αριθμούς σε strings και αντίστροφα, αναλόγως τα συμφραζόμενα. Αυτό μπορεί να είναι ένα πανίσχυρο προγραμματιστικό βοήθημα ή μια τεράστια πηγή σύγχυσης αναλόγως του πόσο συχνά το ξεχνάτε…

Αρκετά όμως με τους scalar operators.

Όταν χρησιμοποιείτε operators σε arrays, η Perl μπορεί να διαχειρίζεται αυτά τα arrays με αρκετούς τρόπους. Το παρακάτω παράδειγμα δείχνει πώς να "εξάγετε" (pop) και να "εισάγετε" (push) μοναδικά array στοιχεία:

@Jedi = ("Yoda", "Obi Wan");
# μερικοί Jedi Knights.
push (@Jedi, "Anakin");
# O νεαρός Anakin εισάγετε στο Τάγμα
$gone_to_the_dark_side = pop (@Jedi); # Τώρα ο Anakin δεν είναι πλέον ένας Jedi

Μετέπειτα υπάρχουν και οι operators για τον χειρισμό των hashes. Εντολές όπως οι παρακάτω είναι αρκετά συχνές σε Perl scripts:

while(($Actor, $Character) = each (%STAR_WARS_CAST));
# ή επίσης
@ACTORS_ONLY = keys(%STAR_WARS_CAST);

Η πρώτη γραμμή θα επαναληφθεί στο %STAR_WARS_CAST hash, κάθε φορά τοποθετώντας το τρέχον κλειδί και την αντίστοιχη τιμή του σε ένα ζευγάρι από scalars ($Actor και $Character), τα οποία μπορούν μετά να επεξεργαστούν όπως θέλετε εσείς. Ο key operator χρησιμοποιείται όποτε θέλετε να σώσετε μόνο τα κλειδιά ενός hash σε μία διαφορετική δομή δεδομένων ώστε να τα επεξεργαστείτε από εκεί μετέπειτα.

Τεκμηρίωση Perl

Η Perl είναι μια ώριμη γλώσσα και οι χρήστες της έχουν δημιουργήσει έναν πλούτο εκτεταμένης τεκμηρίωσης. To βιβλίο Programming Perl του Larry Wall, John Orwant και Tom Christiansen (O'Reilly) είναι μια εξαιρετική αφετηρία. Δείτε το το http://perl.oreilly.com εάν ψάχνετε έναν πιο συγκεκριμένο τίτλο. Για πρόσβαση σε online τεκμηρίωση, συλλογές module, tutorials και τεχνικούς οδηγούς επισκεφθείτε το Comprehensive Perl Archive Network (www.cpan.org).

Δώσε αστέρια!

MO: 4.5 (ψήφοι: 2)