Einführung in die Programmiersprache Perl Teil 2: Binäre Stringoperatoren Zuweisungsoperatoren Zeichen und Zahlen Geordnete Listen und Arrays Assoziative Listen (Hashes) Kontext Referenzen auf Variablen 4.2.2011/11.2.2011
Binäre Stringoperatoren (1) Der Punkt-Operator. verknüpft zwei Zeichenketten miteinander. Der Zeichenketten links und rechts des Punktes werden in dieser Reihenfolge miteinander verbunden. Beispiel: my $foo = "Hello"; my $bar = $foo. " World" $bar hat danach den Wert: "Hello World". Das Verketten von Zeichenketten wird in der Fachsprache Konkatenation (engl. concatenation) genannt.
Binäre Stringoperatoren (2) Der x-operator vervielfacht eine Zeichenkette. Links vom Operator x muss eine Zeichenkette stehen und rechts davon eine ganze Zahl n. Das Ergebnis besteht aus einer Verkettung von n Kopien der Zeichenkette. Beispiel: my $foo = "Bla" x 5; $foo hat danach den Wert: "BlaBlaBlaBlaBla". Achtung: Der x-operator ist nicht kommutativ!
Zuweisungsoperatoren (1) Wir kennen bereits den Zuweisungsoperator =. Beachte: Es handelt sich dabei nicht um ein Gleichheitszeichen im mathematischen Sinne. Der Zuweisungsoperator wertet zuerst den Ausdruck rechts aus (rvalue) und ordnet anschliessend diesen Wert der links stehenden Variable (lvalue) zu. Beispiel: $a = 3.1415 * 10**2; Übungsfrage: Wie interpretiert Perl den folgenden Ausdruck? 7 = $a; Perl wertet die Variable $a aus und möchte diesen Wert der Variable 7 zuordnen. Da 7 jedoch kein gültiger Variablenname ist, bricht Perl die Kompilierung mit einer Fehlermeldung ab.
Zuweisungsoperatoren (2) Perl und viele andere Programmiersprachen kennen Zuweisungsoperatoren, bei denen vor der Zuweisung noch eine Operation mit dem lvalue und dem rvalue ausgeführt wird. my $a = 5; $a += 3; # => $a = $a + 3 => $a = 8 my $b = 7; $b -= 3; # => $b = $b - 3 => $b = 4 my $c = 2; $c *= 3; # => $c = $c * 3 => $c = 6 my $d = 6; $d /= 3; # => $d = $d / 3 => $d = 2 my $e = 8; $e %= 3; # => $e = $e % 3 => $e = 2 my $f = 3; $f **= 3; # => $f = $f ** 3 => $f = 27 my $g = x ; $g.= y ; # =>... $g = xy Es gibt noch 8 weitere solcher Zuweisungsoperatoren, die jedoch erst bei Bedarf erläutert werden. Moral: Diese kombinierten Zuweisungsoperatoren machen den Code vielleicht etwas kürzer aber nicht unbedingt besser lesbar.
Vermischen von Zeichen und Zahlen (1) Da sowohl Zahlen als auch Zeichenketten von Perl als skalare Daten betrachtet werden, fragt man sich vielleicht, was geschieht, wenn man versucht, einen numerischen Operator auf Zeichenketten anzuwenden oder eine Stringoperator auf Zahlen anzuwenden? Perl behandelt das Problem in einer lockeren und naheliegenden Weise. Führe das Programm auf der folgenden Folie vom Perl-Interpreter aus.
prog-02-01.pl 1 #!/ usr / bin / perl 2 3 use strict ; 4 # use warnings ; 5 6 print "7" + " 3", "\n"; 7 print "7" + "3 zahl ", "\n"; 8 print "7" + " zahl3 ", "\n"; 9 print 7 * "5-4", "\n"; 10 print 7. 3, "\n"; 11 print 7. 3, "\n"; Welche Regeln beim Operieren mit gemischten Daten vermutest du aufgrund der Ausgabe?
Vermischen von Zeichen und Zahlen (2) (a) Falls eine Zahl dort steht, wo eine Zeichenkette erwartet wird, wandelt Perl die Zahl in eine Zeichenkette um. 2. 3 "2". "3" "23" (b) Falls ein String dort steht, wo eine Zahl erwartet wird, versucht Perl die Zeichenkette als Zahl zu interpretieren: Führende Leerzeichen oder Tabulatoren werden ignoriert. 5 + " 1.2" 5 + "1.2" 5 + 1.2 6.2 Falls danach Zeichen folgen, die vernünftig als Zahlen gedeutet werden können (dazu gehören auch die Vorzeichen + oder -), wandelt Perl diese Zeichen bis zum nächsten nicht numerischen Zeichen in eine Zahl um. Die übrigen Zeichen im String werden ignoriert. 2 + "3.14abc" 2 + 3.14 5.14 Falls am Anfang des Strings keine Zeichen stehen, die als Zahlen aufgefasst werden können, verwendet Perl den Wert 0. 2 + "abc3.14" 2 + 0 2
Übung Welchen Wert haben die folgenden Perl-Ausdrücke? 1. "12" + 3; => 15 2. "12". 3; => "123" 3. "7x" * "3y"; => 7 * 3 = 21 4. "fun4you" - "5th Avenue"; => 0-5 = -5 5. 4 * "3 Musketiere"; => 12
Was sind Listen? Eine Liste ist eine geordnete Sammlung skalarer Werte. Darstellung im Quellcode: Eine durch Kommas getrennte Aufzählung skalarer Werte oder Ausdrücke, die von einem Paar runder Klammern eingeschlossen ist. Beispiele: (1, 2, 3, 4) Liste aus vier Werten ( a, 9, "blue") Liste aus drei Werten (4+5, $abc, 3) Liste aus drei Werten Beantworte die folgende Frage aufgrund der obigen Beispiele: Müssen die Elemente einer Perl-Liste homogen (d.h. vom gleichen Datenyp) sein? Nein, In einer Perl-Liste dürfen Gleitkommazahlen, ganze Zahlen, Zeichenketten, Referenzen und Ausdrücke gemischt auftreten.
Listen als Argument von print Im Zusammenhang mit der Funktion print() sind wir bereits mit Listen in Kontakt gekommen. print() nimmt als Argument eine Liste entgegen und gibt deren Argumente der Reihe nach aus: print("die Summe beträgt ", $x, " Fr.\n"); print() weiss, dass jetzt eine Liste kommen muss und erlaubt dem Programmierer, die äusseren runden Klammern wegzulassen. print "Die Summe beträgt ", $x, " Fr.\n"; Achtung: es gibt Fälle, wo man vorsichtig mit dieser Nachlässigkeit sein muss ( Übungen)
Verschachtelte Listen Eine verschachtelte Liste ist eine Liste innerhalb einer Liste. Perl löst innere Listen automatisch auf. Man spricht in diesem Zusammenhang auch vom Verflachen von Listen. Beispiel: (1, 2, (3, 4, 5), 6) wird automatisch zu (1, 2, 3, 4, 5, 6) Manchmal ist dieses Verhalten unerwünscht. Wir werden später erfahren, wie man dieses automatische Auflösen innerer Listen mit Hilfe von Referenzen verhindert.
Listen aus Wort-Strings Manchmal müssen Listen aus einfachen Zeichenketten mit Hochkommas gebildet werden. Beispiel: ( eins, zwei, drei, vier ) Bei längeren solchen Listen, kann der Code wegen der vielen Kommas und Hochkommas unleserlich werden und das Risiko von Tippfehlern steigt. Die Funktion quote() hilft dabei, dieses Problem etwas zu entschärfen. quote() nimmt als Argument eine Liste von Zeichenketten, die durch Leerzeichen (Space, Tabulator, Return) getrennt sind und macht damit eine Liste aus Zeichenketten in Hochkommas: qw(eins zwei drei vier) ist dasselbe wie ( eins, zwei, drei, vier )
Listenvariablen = Arrays Auch eine Liste kann in einer Variable gespeichert werden. Variablennamen für Listen beginnen mit dem Typensymbol @. Man denke an ein stilisiertes a wie array dem englischen Wort für Liste oder Vektor. Für Variablennamen von Listen gelten dieselben Regeln wie für skalare Variablen. Um eine Liste einer Listenvariable zuzuweisen, verwendet man den Zuweisungsoperator. Beispiele: @foo = (1, 2, three ); @bar = ($a, $b, 3+4); @kopie = @foo; In Perl bezeichnet man eine Listenvariable als Array.
Bildliche Darstellung my @array = (42, 13, 2) @array 42 13 2 $array[1] Möchte man auf ein einzelnes Element des Arrays zugreifen, wird das @-Zeichen durch das $-Zeichen ersetzt (warum?) und der Index des betreffenden Elements in eckigen Klammern dahinter gesetzt. Achtung: Die Indizierung (=Nummerierung) der Arrayelemente beginnt bei Perl und den meisten anderen Programmiersprachen bei Null!
Übung my $a = 3; my @b = ( x, 3.14, 5 * 8, $a); Welchen Wert hat der Ausdruck? 1. $b[1] => 3.14 2. $b[2] => 40 3. $b[0]. "yz" => "xyz" 4. $b[3]. "8" => "38" 5. $b[4] => Fehlermeldung 6. $b[-2] => 40 Ein negativer Index bedeut, dass die Position, vom Listenende in Richtung des Listenanfangs gezählt wird.
Namenskonflikte? Perl kann skalare Variablen und Listenvariablen mit gleichem Namen (aber entsprechendem Typensymbol) unterscheiden. Warum? my @foo = (5, 6, 7, 8, 9); my $foo = 42; @foo Liste (5, 6, 7, 8, 9); wegen @-Symbol $foo Skalar 42; wegen $-Symbol $foo[3] Element 8 der Liste; wegen [...]
Mehrfachzuweisungen Listen können auch im Zusammenhang mit Zuweisungen auftreten. Was bewirken die folgenden Ausdrücke? my ($a, $b) = (35, 12); => my $a = 35; => my $b = 12; ($a, $b) = ($b, $a); => $a = 12 => $b = 35 Warum funktioniert das? Weil die Ausdrücke rechts vom Zuweisungsoperator vor der Zuweisung ausgewertet werden.
Der Bereichsoperator Einfache Folgen von Zahlen oder Buchstaben können in Perl mit dem Bereichsoperator.. (range operator) erzeugt werden: (3.. 7) => (3, 4, 5, 6, 7) ( a.. g ) => ( a, b, c, d, e, f, g ) (0.. 9, A.. F ) => (0, 1,..., 9, A, B,..., F ) ( aa.. zz ) => ( aa, ab,..., az, ba, bb,..., bz,... za, zb,..., zz ) (7.. 4) => () [da 7 > 4]
Slices (1) Führe das Programm prog-02-02.pl aus und versuche die Ausgabe zu verstehen. my @a = ( 1, 2, 3, 4, 5, 6 ) ; my @b = @a [ 1, 3, 4 ] ; my @c = @a [ 0.. 4 ] ; my @d = ( a.. z ) ; my @e = @d [ @a ] ; p r i n t a : @a\n ; p r i n t b : @b\n ; p r i n t c : @c\n ; p r i n t d : @d\n ; p r i n t e : @e\n ;
Slices (2) Werden innerhalb der eckigen Klammern mehrere Indizes angegeben, so geht Perl davon aus, dass die entsprechenden Elemente aus dem Array ausgewählt werden. Da es sich bei der Auswahl von mehr als einem Element wieder um eine Liste handelt (Teilliste oder slice), muss als Typensymbol des Rückgabwerts das @-Symbol verwendet werden. Der Bereichsoperator wird sinnvollerweise dort eingesetzt, wo ein zusammenhängender Bereich aus einem Array ausgwählt werden soll.
Übungen my @array = (3, 4, 5, 6, 7, 8, 9); 1. @array[0,2,4] => (3, 5, 7) 2. ( a.. z, A.. Z ) => (a, b,..., z, A, B,... Z) 3. @array[-2.. -4] => keine Ausgabe, da (-2) > (-4) 4. @array[-4.. -2] => (6, 7, 8)
Arrayoperationen (1) shift ARRAY Diese Funktion bewirkt folgendes: Schiebt das erste (d. h. das nullte ) Element aus dem Array heraus und gibt es als Funktionswert zurück. Verkürzt das Array um ein Element und rückt alle Elemente um eine Position nach vorne. Beispiel: my @array = (3, 4, 5, 6, 7); my $wert = shift(@array); @array hat danach den Wert: (4, 5, 6, 7) $wert hat danach den Wert: 3
Arrayoperationen (2) unshift ARRAY, LIST Die Funktion unshift ist so etwas wie ein Gegenspieler von shift: unshift schiebt die Elemente von LIST von vorne in die Liste mit dem Variablennamen ARRAY Der Wert von unshift ist nicht der veränderte ARRAY sondern die neue Anzahl der Elemente in ARRAY. Beispiel: my @array = ( x, y, z ); my $wert = unshift @array, ( a, b ); @array hat danach den Wert: ( a, b, x, y, z ) $wert hat danach den Wert: 5
Arrayoperationen (3) pop ARRAY Die Funktion pop bewirkt folgendes: Entfernt das letzte Element aus dem Array und gibt es als Funktionswert zurück. Verkürzt das Array um das letzte Element. Beispiel: my @array = (3, 4, 5, 6, 7); my $wert = pop(@array); @array hat danach den Wert: (3, 4, 5, 6) $wert hat danach den Wert: 7
Arrayoperationen (4) push ARRAY, LIST push ist so etwas wie ein Gegenspieler von pop: push hängt die Elemente von LIST an das Ende von ARRAY an. Der Wert von push ist die neue Anzahl der Elemente in ARRAY. Beispiel: my @array = ( a, b ); my $wert = push @array, c ; @array hat danach den Wert: ( a, b, c ) $wert hat danach den Wert: 3
Zusammenfassung shift... unshift push pop @ARRAY
Übung Wie sieht das Array @liste nach jeder Operation aus? my @liste = (4, 5, 6); 1. push(@liste, 11, 12); => @liste = (4, 5, 6, 11, 12) 2. shift(@liste); => @liste = (5, 6, 11, 12) 3. pop(@liste); => @liste = (5, 6, 11) 4. unshift(@liste, 13, 14, 15); => @liste = (13, 14, 15, 5, 6, 11)
Hashes (1) Es ist nicht immer sinnvoll, eine Sammlung von Daten in Form einer nummerierten Liste anzulegen. Beispiel: my @person = ( Meier, Tim, Heimweg 7, 6370, Stans ); Mit $person[0] kann man auf den Familennamen oder mit $person[3] auf die Postleitzahl der Person zugreifen. Sind diese Bezeichnungen in einem Programm selbsterklärend?
Hashes (2) Es gibt Situationen, in denen man die Daten einer Datenmenge besser mit einem Etikett als mit einer Nummer identifiziert. Diese Art von Datenstruktur wird in der Informatik auch als assoziative Liste oder Menge von Schlüssel/Wert-Paaren genannt. Auf das Beispiel von vorhin angewendet: Schlüssel Wert name "Meier" vorname "Tim" strasse "Heimweg 7" plz "6370" ort "Stans"
Hashes (3) Perl kennt assoziative Listen als eigenen Datentyp. Im Gegensatz zu Listen müssen assoziative Listen jedoch an eine Variable gebunden werden. Aufgrund der Art und Weise, wie Perl assoziative Listen intern speichert, werden sie Hashes genannt. Das Typensymbol für eine Hash-Variable ist das Prozentzeichen (%). (Man kann sich das so merken, dass das Kreislein oben links den Schlüssel und das Kreislein unten rechts den Wert darstellt.)
Hashes (4) Hash-Variablen werden über den Umweg einer Liste definiert: my %person = ( name, "Meier", vorname, "Tim", strasse, "Heimweg 7", plz, "6370", ort, "Stans"); Jeweils zwei aufeinanderfolgende Elemente einer Liste bilden in dieser Reihenfolge ein Schlüssel/Wert-Paar. Man kann sich gut vorstellen, dass die oben gezeigte Art der Eingabe schnell zu Fehlern führt: Komma vergessen Apostroph vergessen Schlüssel vergessen Wert vergessen
Hashes (5) In Perl gibt es das Synonym => für das Komma. In diesem Fall dürfen auch die Hochkommas der Schlüssel weggelassen werden. my %person = (name => "Meier", vorname => "Tim", strasse => "Heimweg 7", plz => "6370", ort => "Stans"); Durch Leerzeichen und Zeilenschaltungen können wir die Eingabe noch übersichtlicher formatieren: my %person = (name => "Meier", vorname => "Tim", strasse => "Heimweg 7", plz => "6370", ort => "Stans");
Zugriff auf Hashes Um beispeilsweise auf den Vornamen in unserem Beispieldatensatz zuzugreifen, verwenden wir die folgende Syntax: $person{vorname} Wir geben den Schlüsselnamen in geschweiften Klammern hinter dem Variablennamen an. Aus dem Typensymbol % wird das Typensymbol $. Warum? Ein einzelner Werte ist in Perl ein Skalar und skalare Variablen haben das $-Zeichen als Typensymbol. Bemerkung: Die Hochkommas um den Schlüsselnamen können in der Regel weggelassen werden. Dieselbe Schreibweise wird auch dazu verwendet einem Schlüssel einen neuen Wert zuzuordnen: $person{vorname} = "Timothy";
Die Funktion keys keys HASH Liefert eine Liste, die aus allen Schlüsseln des angegebenen Hashes besteht. Im skalaren Kontext (dazu bald mehr) liefert die Funktion die Anzahl der Schlüssel. Achtung: Die Schlüssel werden in scheinbar zufälliger Reihenfolge ausgegeben. Beispiel: my %person = (name => "Meier", vorname => "Tim", strasse => "Heimweg 7", plz => "6370", ort => "Stans"); my @liste = keys(%person) print "@liste"; Ausgabe: ort vorname strasse plz name
Die Funktion values values HASH Liefert eine Liste, die aus allen Werten des angegebenen Hashes besteht. Im skalaren Kontext liefert die Funktion die Anzahl der Schlüssel (dazu bald mehr). Achtung: Die Werte werden in derselben zufälligen Reihenfolge wie bei keys ausgegeben. my %person = (name => "Meier", vorname => "Tim", strasse => "Heimweg 7", plz => "6370", ort => "Stans"); my @liste = values(%person) print "@liste"; Ausgabe: Stans Tim Heimweg 7 6370 Meier
Hash-Slices my %person = (name => "Meier", vorname => "Tim", strasse => "Heimweg 7", plz => "6370", ort => "Stans"); my @liste = @person{ vorname, name }; print "@liste"; Ausgabe: Tim Meier
Die Funktion delete delete EXPRESSION Löscht das (oder die) Schlüssel/Wert-Paar(e) aus dem Hash, gemäss der EXPRESSION. Die Funktion liefert eine Liste mit den gelöschten Werten zurück. my %person = (name => "Meier", vorname => "Tim", strasse => "Heimweg 7", plz => "6370", ort => "Stans"); my @liste = delete $person{vorname}; print "@liste"; Ausgabe: "Tim"; [ genauer: ("Tim") ]
Kontext (1) Perl unterscheidet primär zwischen skalaren Werten und Listen. Diese Trennung geht über die Schreibweise von Variablen hinaus. Sie beeinflusst auch die Art und Weise, wie gewisse Ausdrücke ausgewertet werden. Dazu ein erstes Beispiel: @foo = (7, 8, 9); $bar = @foo; In der ersten Zeile erwartet das Array @foo, dass ihm eine Liste zugewiesen wird. Das Array erwartet eine Liste, also wird der Ausdruck (korrekt) im Listenkontext ausgewertet. Analog dazu erzeugt die skalare Variable $bar einen skalaren Kontext, weil sie rechts einen skalarer Wert erwartet. Nun steht dort aber eine Liste. Perl erzwingt nun diesen skalaren Kontext, indem er an Stelle der Liste die Anzahl der Elemente der Liste setzt.
Kontext (2) Was geschieht umgekehrt, wenn wir einem Array einen skalaren Wert zuweisen wollen? @foo = 12; Da das Array einen Listenkontext erzeugt, verwandelt Perl den skalaren Wert 12 in die Liste (12), die nur aus einem Element besteht. Dasselbe hätten wir auch gleich mit der Zuweisung @foo = (12); erledigen können.
Kontext (3) Offenbar liefern einige Perl-Funktionen unterschiedliche Werte zurück und zwar in Abhängigkeit davon, ob sie im skalaren- oder im Listenkontext aufgerufen werden. Als letztes Beispiel soll hier noch der Komma-Operator dargestellt werden. Listen-Kontext: Die Argumente links und rechts des Kommas werden ausgewertet und in eine Liste eingefügt. Bei mehr als einem Komma finden dieser Vorgang von links nach rechts statt. @foo = (1, 3 + 5, 4); # => @foo = (1, 8, 4) Skalarer Kontext: Der Komma-Operator wertet das linke Argument aus und wirft den Wert weg. Danach wird das rechte Argument ausgwertet und dessen Wert zurückgegeben. Bei mehreren Kommas verhält sich der Operator ebenfalls linksassoziativ. $foo = 1, 3 + 5, 4; # => $foo = 4
Referenzen auf Variablen (1) Wir haben früher bereits erwähnt, dass man in einer skalare Variable auch eine Referenz, d. h. die Adresse eines bestimmten Speicherplatzes ablegen kann. Wir haben aber nie erklärt, wie man das macht. Zunächst benötigen wir die Vorstellung, dass eine Variable ein Behälter (Speicherplatz) mit einem Namen und einer Adresse ist. Eine Referenz auf eine (skalare) Variable ist eine skalare Variable, die als Wert die Adresse des Speicherplatzes der Variable enthält, auf die sie verweist. Dazu ein Bild: $foo 42 $foo ref
Referenzen auf Variablen (2) Wann immer Perl auf einen Ausdruck wie $foo trifft, erwartet es nach dem $-Symbol etwas, was zu einer Adresse für eine skalare Grösse ausgewertet werden kann. Perl sucht in seiner internen Liste der skalaren Variablen nach dem Namen foo. Falls es ihn findet, wird foo durch die entsprechende Adresse ersetzt und der skalare Wert von dieser Stelle gelesen bzw. bei Zuweisungen an diese Stelle geschrieben. Perl erlaubt es uns nun, die Adressen, wo normale Variablen ihre Werte speichern, in einer weiteren skalaren Variable zu speichern. An die Adresse einer Variablen kommt man mit dem Backslash-Operator: my $foo = 42; my $bar = \$foo; # $bar bekommt die Adresse von $foo
Referenzen auf Variablen (3) Wir müssen uns bewusst sein, dass eine Referenz zunächst keinen direkten Zugang zu der Variablen ermöglicht, auf die sie zeigt. Möchte man den Wert einer Referenz ausgeben, so erhält man zunächst eine Adresse. Um nun indirekt an den Wert der Variablen zuzugreifen, auf den die Referenz zeigt, muss die Referenz dereferenziert werden, indem man das jeweiligen Typensymbol vor die Referenzvariable setzt. Zeigt die Referenz $bar auf die Variable $foo, so bekommt man mit $$bar den Wert von $foo: my $foo = 42; my $bar = \$foo; print $bar; # Ausgabe der Adresse SCALAR(0x18334e4) print $$bar; # Ausgabe des Wertes 42
Referenzen auf Variablen (4) Auch Referenzen auf Arrays sind skalare Variablen. In gewisser Weise genügt es, dass die Referenz auf das erste Element eines Arrays zeigt. my @array = (5, 8, 2); @array $array ref = \@array; $array ref 5 8 2 Um eine Referenz auf einen Array zu dereferenzieren, muss das Typensymbol @ vor die Referenzvariable gesetzt werden.
Referenzen auf Variablen (5) Bis zu diesem Punkt ist es nur wichtig, das Konzept der Referenzen zu verstehen. Die Nützlichkeit von Referenzen wird erst in den folgenden Lektionen deutlich, wenn es darum geht, Parameter an Funktionen zu übergeben oder Datenstrukturen zu erzeugen.