Perl 1

Perl 2

Perl 3

Perl 4

Perl 5

Perl 6

Zurück

Einführung in Perl - Teil IV

Felder in Perl

von Achim Schmidt


In den letzten Folgen unserer Perl-Serie habe wir uns bereits das Variablenhadling, Kontrollstrukturen und reguläre Ausdrücke angesehen, sowie einige Perl-Funktionen. Im heutigen Teil geht es um Felder und was man mit ihnen alles anstellen kann.

Was ist ein Feld?

Ein Feld oder Array, ist eine Liste skalarer Daten, wobei jedes einzelne Element eine eigene, unabhängige Skalarvariable darstellt. Felder können aus einer unbestimmten Anzahl einzelner Elemente bestehen. Die maximale Obergrenze an Einzelelementen ist dabei lediglich durch den verfügbaren Hauptspeicher begrenzt.

Schreibweise von Arrays

Einem Array, wird ähnlich einer Variable, ein eigener symboischer Name zugeordnet, welcher die komplette Liste der Einzelausdrücke umfaßt. Im Gegensatz zu Variablennamen, welche einheitlich mit dem Dollarzeichen $ beginnen, verwendet man als einleitendes Zeichen für Arrays den Klammeraffen @. Damit ist eine klare Abgrenzung zu Variablen hingegeben und es können sowohl Variablen und Arrays mit gleichem Namen in friedlicher Koexistenz nebeneinander existieren. Durch den Unterschied des ersten Zeichens ist eine eindeutige Definition des Bezeichners gegeben.

Zuweisung von Elementen

Wie bereits erwähnt sind Arrays nichts anderes als Listen einzelner Elemente. Eine entsprechende Zuweisung der Elemente in das Array sieht demnach folgendermaßen aus:
@namen = ("Hans","Stefan","Michael","Thomas");
Obige Zuweisung erzeugt also ein Feld @namen, welches die Elemente Hans, Stefan, Michael und Thomas enthält. Wie sie richtig annehmen, sind die Einzelelemente vom Typ String, was aber unerheblich ist, da sich, wie auch schon bei Variablen, der Elementtyp nicht nach einer Deklaration, sondern nach der eigentlichen Zuweisung richtet.

Das komplette Literal, sprich der Feldinhalt, wird erst bei dessen Benutzung neu initiiert, wodurch nun auch die Benutzung von Variablen innerhalb der Zuweisung gestattet ist. Das bedeutet, daß bei jeder Zuweisung eine entsprechende Variablenersetzung stattfindet. Demnach sind also auch Zuweisungen der Form:

@namen = ("Stefan","Thomas",$name3,$name4);
erlaubt. Dabei werden bei der Zuweisung die Variablen $name3 und $name4 durch deren aktuelle Werte ersetzt und im Array abgelegt.

Darüberhinaus ist es auch möglich, Arrys komplette Felder zuzuweisen. Eine Zuweisung der Form:

@namen = @vornamen ;
würde im Array @namen alle im Feld @vornamen enthaltenen Elemente abbilden, während eine Zuweisung der Form:
@namen = ($name1,$name2,@vornamen) ;
dem Array @namen als erste beide Elemente die Inhalte der Variablen $name1 und $name2, sowie nachfolgend alle im Array @vornamen enthaltenen Elemente zuweisen. Dagegen wirkt folgende Zuweisung genau in entgegengestzter Richtung:
@namen = (@vornamen,$name1,$name2) ;
Hier werden vor der Zuweisung der Inhalte von $name1 und $name2, die Einzelelemente des Arrays @vornamen in das neue Feld @namen zugewiesen.

Erweitern eines bestehenden Arrays

Um einem bestehenden Array neue Elemente anzufügen, gibt es nun mehrere Arten. Die erste ergibt sich eigentlich aus der Möglichkeit, Feldern Arrays zuzuweisen. Die Zuweisung
@namen = (@namen,$neu_name) ;
fügt den Inhalt der Variablen $neu_name dem Feld @namen hinzufügen, und zwar am Ende der bestehenden Liste. Das funktioniert natürlich auch mit mehreren Einzelelementen, in dem diese einfach innerhalb der Klammer, durch Kommata getrennt, aneinandergereiht werden. Die gleiche Funktion erfüllt die Funktion push(). Diese Funktion erweitert ein bestehendes Array um ein oder mehrere neue Elemente.
push (@name,$neuer_wert1,$neuer_wert2);
fügt die Inhalte der beiden Variablen am Ende der Liste im Array @name hinzu.

Elemente aus bestehenden Arrays entfernen

Auch das Entfernen von Elementen wird uns durch eine spezielle Perl-Funktion abgenommen. Es handelt sich dabei um die Funktion pop(), welche das letzte Element aus einem Array entfernt. Der Funktionsaufruf ist dabei denkbar einfach. Der Funktion wird dazu nämlich einfach das betreffende Array übergeben. Als Rückgabewert liefert die Funktion dabei das entfernte Element.
$last_name = pop(@namen) ;
Nach erfolgreicher Ausführung der Funktion enthällt $last_name das letzte Element des Feldes @namen, aus welchen dieses entfernt wird. Wird der Funktion dabei ein leere Feld übergeben, so wird als Rückgabewert undef geliefert. Die Programmausführung wird dabei jedoch nicht beeinflußt.

Weitere Operationen der Arraybearbeitung

Neben den erwähnten Funktionen push() und pop() stellt Perl jedoch noch eine Reihe weiterer Funktionen zur Verfügung. Als erstes möchte ich dabei die beiden Funktionen shift() und unshift() erwähnen, welche ähnlich push() und pop() arbeiten. Während die bereits besprochenen Funktionen die 'rechte' Seite einer Liste bearbeiten, tun shift() und unshift() dies mit der 'linken' Seite eines Feldes, also dem Anfang eines Feldes. Die Funktion unshift() ist dabei das Äquivalent zu push(), d.h. es fügt ein neues Element an die linke Seite einer Liste bei:
unshift (@namen,$neu_name) ;
bewirkt also das gleiche wie
@namen =($neu_name,@namen) ;
es fügt ein neues Element an den Anfang eines bestehenden Arrays hinzu. Die Perl Funktion shift() ist dementsprechend das Äquivalent zu pop() für die linke Seite eines Feldes, sprich es entfernt das erste Element aus einem bestehenden Array und liefert dabei das entfernte Element wiederum als Rückgabe zurück.
$first_name = shift(@namen) ;
Eine weitere Funktion zum Bearbeiten von Arrays ist die Funktion reverse(), welche die Reihenfolge der einzelnen Elemente umdreht und als Rückgabewert liefert. Dabei bleibt das eigentliche Array im bisherigen Zustand komplett erhalten.

Die Funkion wird durch folgendes kleines Beispielprogramm wohl am besten verdeutlicht:

#!/usr/bin/perl

@namen = ("Paul","Stefan","Michael","Hans");
print "@namen\n";
@namen = reverse (@namen);
print "@namen\n";
In dem Programm wird die Ausgabe der reverse() Funktion wieder dem Feld @namen zugewiesen, so daß die Elemente in diesem Feld umgedreht werden.

Die Funktion sort() arbeitet ebenfalls mit Arrays und liefert als Ausgabe eine sortierte Liste des übergebenen Arrays. Sehen wir uns das doch am besten wieder an einem kleinen Beispiel an:

#!/usr/bin/perl

@namen = ("Paul","Stefan","Michael","Hans");
print "@namen\n";
@namen = sort (@namen);
print "@namen\n";
Das Programm arbeitet analog zum ersten Beispiel, mit dem Unterschied, daß nun die Liste nicht gedreht wird, sondern sortiert wird.

Als nächstes möchte ich nochmals auf die Funktion chop() eingehen, welche ich bereits in einem früheren Teil erläutert habe. Dort jedoch im Bezug auf einzelne Variablen. Wendet man diese Funktion auf ein komplettes array an, so wird von jedem Einzelelement der Liste das letze Zeichen entfernt. Dies kann im Zusammenhang mit Eingaben, welche durch RETURN abgeschloßen sind recht nützlich ein. Denn auch der <STDIN> Operator kann auf Arrays angewand werden. Dazu weist man ihn einfach einem Array anstelle einer Variablen zu. Die Eingabe wird durch EOF (End Of File) abgeschloßen, was bei Tastatureingaben durch Control-D bewirkt wird. Das folgende Beispiel zeigt die Anwendung beider Funktionen:

#!/usr/bin/perl

@namen = <STDIN> ;
print "\n\n@namen\n";
@namen = sort(@namen);
chop(@namen);
print "\n\n@namen\n";
Das Programm liest zunächst Zeichenkette via der Standardeingabe ein, und gibt diese Eingaben dann wieder aus. Anschließend werden diese sortiert und durch die Zeile
chop(@namen);
wird von jedem Element der Liste das letzte Zeichen, in diesem Fall das RETURN, entfernt. Anschließend wird die sortierte, von RETURN befreite, Liste erneut ausgegeben.

Zugriff auf einzelne Listenelemente

Bislang haben wir uns nur das Array als solchen angesehen, also nur das komplette Konstukt betrachtet. Selbstverständlich ist jedoch auch ein Zugriff auf einzelne und bestimmte Elemente möglich.

Zugriff auf ein bestimmtes, einzelnes Element eines Feldes erhält man, indem es gezielt angesprochen wird. Dieses gezielte Adressieren geschieht, indem die entsprechende Nummer des gewünschten Elementes in eckigen Klammern hinter den Feldnamen gesetzt wird. Dabei ist zu beachten, daß nun kein Array mehr angesprochen wird, sondern ein einzelner skalarer Datentyp, also eine normale Variable. Die Anweisung

print $namen[0];
würde also das erste Element des Feldes @namen ausgeben. Auf die gleiche Art und Weise kann auch gezielt der Wert eines Elementes innerhalb eines Feldes geändert werden. Dies geschieht durch eine entsprechende Zuweisung:
$namen[2] = $neu_name ;
Diese Anweisung, würde demnach dem dritten Element des Feldes @namen den in der Variablen $neu_namen enthaltenen Wert zuordnen. Wie Sie sicher bereits gemerkt haben, wird das erste Element mit [0] angesprochen. Wie Sie richtig erkannt haben, beginnt mal beim Zählen der einzelnen Elemente innerhalb von Arrays nicht mit der Ziffer eins, sondern wie es in der Informatik üblich ist, mit Null.

Mit diesen gezielten Zugriffen auf Arrayelemente kann man nun wie mit normalen skalaren Variablen gearbeitet werden, da es sich aus der Perlschen Sichtweise auch um ganz normale Variablen handelt. Auf diese Weise ist es recht einfach möglich die Inhalte zweier Arrayelemente zu vertauschen. Dies geschieht einfach durch folgende Anweisung:

($namen[2],$namen[3]) = [$namen[3],$namen[2]);
Diese Anweisung tauscht die Elemente drei und vier des Elementes @namen.

Sehen wir uns das Arbeiten mit Feldern an einem weiteren Beispiel an:

#!/usr/bin/perl

$vname="run";

while ($vname) {
   print "Vorname:  "; chop ($vname = <STDIN>);
   if ($vname) {
      print "Nachname: "; chop ($nname = <STDIN>);
      push (@vornamen,$vname); push (@nachnamen,$nname); 
   }
}

print "\n\n";
$i = 0;
while ($vornamen[$i]) {
   print "$vornamen[$i] $nachnamen[$i]\n";
   $i++ ;
}
print "\n\n";
Das Programm liest Vor- und Nachnamen von der Tastatur ein, bis als Vorname eine leere Eingabe (also nur RETURN) eingegeben wird. Die Namen werden in unterschiedliche Variablen eingelesen und in gleicher Reichenfolge in zwei verschiedene Arrays abgelegt. Dies macht eine Zurodnung anhand der entsprechenden Elementnummern innerhalb der Arrays möglich, was anschließend in der Ausgabeschleife genutzt wird.

Assoziative Arrays

Nehmen wir das obige Beispiel einmal, und stellen und vor, daß wir anstelle des Vornamens eine eindeutige Kundennummer haben, nach der wir entsprechend suchen wollen. Das ganze geht nach obigem Schema nur, indem man innerhalb einer Schleife alle eingegebenen Kundennummern durchgeht und mit einem entsprechenden Suchbegriff vergleicht und bei Übereinstimmung ausgibt.

Das Ganze geht jedoch aus etwas einfacher, wenn man dazu eine Sonderform des Arrays, nämlich das Assoziative Array benutzt. Innerhalb eines assoziativen Arrays sind immer Wertepaare der Form Schlüssel,Wert gespeichert. Anhand des Schlüssels kann man nun eindeutig auf den entsprechenden Wert zugreifen. Als einleitendes Zeichen tragen assoziative Arrays das Prozentzeichen, womit wiederum eine eindeutige Zuordnung zum Feldtyp möglich ist.

Auf ein einzelnes Element wird, wie bereits erwähnt anhand des Schlüssels zugegriffen. Dabei sieht ein entsprechender Aufruf so aus:

$wert = $ass_array{"Schlüssel"} ;
Wie Sie sicher bemerkt haben, steht der entsprechende Schlüssel diesmal in geschweiften Klammern. Es muß jedoch kein konstater Wert sein, sondern kann auch eine Variable sein. Am besten sehen wir uns die Funktionsweise eines solchen assoziativen Feldes einmal an einem Beispiel an.
#!/usr/bin/perl

$vname="run";

while ($vname) {
   print "KdNr:  "; chop ($vname = <STDIN>);
   if ($vname) {
      print "Name: "; chop ($nname = <STDIN>);
      %namen = (%namen,$vname,$nname); 
   }
}

print "\n\n";

print "Ges. Kundennummer: " ; chop ($such = <STDIN>);
print "Name: $namen{$such}\n";
Im ersten Block werden die entsprechenden Werte eingelesen und in das assoziative Array geschrieben. Im weiteren Verlauf des Programmes wird nach der zu suchenden Kundennummer gefragt und anschließend dieser Suchtext dem Skalar, welcher sich nun ja auf das angelegte Feld bezeichnet als Schlüssel übergeben und anschließend ausgegeben.

Wie Sie sicher bereits bemerkt haben, wird bei der Ausgabe des gefundenen Suchbegriffes das assoziative Array mit vorangestelltem Dollarzeichen anstelle des Prozentzeichens angesprochen. Dies ist jedoch lediglich eine konstquente Weiterführung der Variablenbenennung in Perl, denn Sie greifen hier ja nicht auf das gesammte Literal zu, sonderen lediglich auf ein einzelnes Element, einen Skalar eben, was Sie Perl mitteilen, indem dem entsprechenden Bezeichner das zugehörige Kennzeichen (hier wiederum das Dollarzeichen) vorangestellt wird.

Neben dieser Möglichkeit bietet Perl jedoch auch noch einige Funktionen an, welche sich auf das komplette Feld beziehen. Die erste Funktion, die ich hier erwähnen möchte ist die Funktion values(). Als Parameter wird ihr der Bezeichner des assoziativen Feldes mitgegeben, während sie als Rückgabe ein normales Array liefert, in welchem jedes Element einem Wert (!!) des assoziativen Arrys entspricht. Es gibt Ihnen also die Möglichkeit, alle Werte (nicht die Schlüssel) auszulesen.

Ein solcher Aufruf könnte also so aussehen:

@werte = values (%namen) ;
Dieser Aufruf liefert also alle Werte des assoziativen Arrays %namen und speichert diese im Array @werte.

Die gegenteilige Funktion, welche eben alle Schlüssel eines assoziativen Arrays liefert, wäre die Funktion keys(). Der Aufruf und die Rückgabe ist analog zu der values() Funktion.

Um nun in einer Schleife alle Elementpaare auszulesen, kann man sich der each() funktion bedienen. Auch sie erhält als einzigen Parameter den Bezeichner des auszulesenden assoziativen Arrays und liefert die entsprechenden Elementpaare zurück:

while ($kdnr,$name) = each (%namen) {
   print "Kundennummer: $kdnr - Name: $name \n";
}
Diese Zeilen lesen also das komplette assoziative Array aus und geben die entsprechenden Elementwerte aus. Somit stellt dies eine recht efektive und einfache Art da, alle Elementpaare auszulesen und eventuell weiterzuverarbeiten.

Löschen einzelner Elementpaare

Nachdem Sie nun kennengelernt haben, wie Elementpaare zugewiesen werden und man auf die entsprechenden Daten zugreifen kann, will ich Ihnen auch nicht verschweigen, wie man gezielt Elementpaare aus dem assoziativen Array löschen kann. Dazu stellt Perl die Funktion delete() zur Verfügung. Da jedoch ein einzelnes Element referenziert wird, greift man wiederum mittels des Skalaroperators auf diese zu. Der Funktion wird lediglich die Referenz auf das zu löschende Elementepaar übergeben:
delete $namen{$todelete};
Dieser Aufruf löscht also das Elementepaar, dessen Schlüssel mit dem Inhalt der Variable $todelete übereinstimmt.

Die Anordnung innerhalb eines assoziativen Arrays können Sie übrigens nicht beeinflußen, da Perl diese intern mit Hash-Tabellen verwaltet, um einen schnellen Zugriff zu ermöglichen.

Sicher haben Sie die Leistungsfähigkeit von Feldern bereits erkannt. In vielen Anwendungen kommt man um diese Funktionen nicht herum, da sie einen relativ einfachen Zugriff auf Daten ermöglichen und oft interne Verarbeitungen erheblich vereifachen.

Der Autor

Achim Schmidt ist staatlich geprüfter Assistent für Automatisierungs- und Computertechnik (HBFS) und beschäftigt sich bereits seit 6 Jahren intensiv mit dem Internet und seinen Diensten. Mit Linux wurde er erstmalig 1992 beim Aufbau eines Mailboxsystemes direkt konfrontiert. Seit 1995 ist er als Netzwerk- und Systemmanager tätig und beschäftigt sich dabei auch mir der Entwicklung und Realisierung WWW- basierter Onlinesysteme und Internetkopplungen. Zu erreichen ist er unter as@Saar.DE.

Copyright © 1997 Linux-Magazin Verlag