Webbasierte Adressdatenbank
Komplexe Datenstrukturen
Referenzen
Perl hat sich traditionell auf lineare Datenstrukturen konzentriert. Es ist in der Regel
auch das, was benötigt wird. Gelegentlich möchte man aber komplexere Datenstrukturen
verwenden, dies ist jetzt in Perl 5 relativ einfach mit "Referenzen" machbar.
Neben der normalen Möglichkeit Variablen mit ihrem Namen anzusprechen, gibt es in Perl
"Referenzen auf Datentypen" d. h. intelligente Zeiger auf Datentypen. Damit
lassen sich sehr einfach Arrays von Arrays (List of Lists - LoL), Arrays von Hashes (LoH),
Hashes von Hashes (HoH) oder noch komplexere Datenstrukturen erzeugen. Außerdem gibt es
auch Referenzen auf Funktionen. Wir wollen hier zum
einen die allgemeinen Verfahren zum "Referenzieren" bzw. zum
"Dereferenzieren" darstellen, zum Anderen werden wir uns im Beispiel auf
LoL
beschränken, da diese Datenstruktur in der ersten Variante
unserer Adressdatenbank Verwendung findet wird.
Die nachfolgende Tabelle zeigt, wie Referenzen erzeugt und verwendet werden:
Verfahren | Erklärung |
---|---|
$scalarref = \$scalar; $scalar = $$scalaref; $scalar = ${$scalarref}; |
Skalar -> Skalarreferenz Skalarreferenz -> Skalar wie oben |
$arrayref = \@array; @array = @$arrayref; @array = @{$arrayref}; $element = S{$arrayref}[3]; $element = $arrayref->[3]; |
Array -> Arreayreferenz Arrayreferenz -> Array wie oben Arrayreferenz -> einzelnes Element wie oben |
$hashref = \%hash; %hash = %$hashref; %hash = %{$hashref}; $wert ${$hashref}{'Schlüssel'}; $wert = $hashref->{'Schlüssel'}; |
Hash -> Hashreferenz Hashreferenz -> Hash wie oben Hashreferenz -> Einzelner Wert wie oben |
$funcref = \&func &$funcref(); $funcref->(); |
Funktion -> Funktionsrerefenz Funktionsreferenz -> Aufruf der Funktion wie oben |
Verwendet man Refrenzen von Arrays oder Hashes um auf einzelne Elemente oder Werte
zuzugreifen, sollte vorwiegend der Pfeiloperator ->
benutzt
werden, da hier die Verwendung der Referenz deutlicher zu Tage tritt.
Beispiel LoL
Im Kapitel Zerlegen von Datensäzen heben wir gesehen, wie
man einen Datensatz als String mit Trennzeichen erzeugt und in einer Datei abspeichert.
Unsere Adressdatenbank wird diese Methode verwenden um die Adressdatensätze zu speichern.
Wie können wir nun eine solche Struktur aus dem File wieder einlesen und z.B. zuerst nach
Nachname und bei Gleichheit noch nach Vorname sortieren, bevor wir die Daten ausgeben? Am
Besten funktioniert das mit LoL. Hier nun einige Code Schnippsel, welche die Verwendung
einer LoL zeigen:
Zusammensetzen einer LoL
@LoL = ( [ "fred", "barney" ], [ "george", "jane", "elroy" ], [ "homer", "marge", "bart" ], );
Man beachte die eckigen Klammern um die einzelnen Zeilenarrays. Dies erzeugt automatisch eine Arrayreferenz!
Generierung einer LoL
# Aus einer Datei while (<FILE>) { push @LoL, [ split ]; }
Auch hier steht das mit split
erzeugte Zeilenarray in eckigen
Klammern um eine Arrayreferenz zu erzeugen. Die Funktion split
wird hier ganz ohne Argumente verwendet, was bedeutet, der aufzutrennende String steht
in $_
, und als Trennzeichen werden Whitspaces /\s+/
verwendet, nachdem alle führenden Whitespaces entfernt wurden.
# Zu einer existierenden Liste hinzufügen push @{ $LoL[0] }, "wilma", "betty";
Wenn wir einem Zeilenarray einer LoL etwas mit push
hinzufügen
wollen, müssen wir das Zeilenarray derefrenzieren, da eine LoL nicht die Zeilenarrays als
echte Arrays beinhaltet, sonder als Arrayreferenzen!
Zugriff und Ausgabe von LoL
# Ein Element $LoL[0][0] = "Fred"; # Ein Anderes Element $LoL[1][1] =~ s/(\w)/\u$1/; # Ausgabe des gesamten Dingsdas mit Referenzen for $array_ref ( @LoL ) { print "\t @$array_ref \n"; } # Ausgabe des gesamten Dingsdas mit Indizes for $i ( 0 .. $#LoL ) { print "\t @{$LoL[$i]} \n"; } # Alle Elemente nacheinander ausgeben for $i ( 0 .. $#LoL ) { for $j ( 0 .. $#{$LoL[$i]} ) { print "element $i $j is $LoL[$i][$j]\n"; } }
Die letzten zwei for
Schleifen nutzen die Eingenschaft von
$#LoL
den Index des Letzten Elementes des Arrays zurückzugeben.
Beispiel Adressen
So, jetzt können wir uns wieder unserer Adressdatenbank zuwenden. Nehmen wir an, wir
hätten folgende Datensätze in der Datei adress.dat
stehen:
Feuerstein|Fred|fred@irgendwo.com Geröllheimer|Betty|betty@irgendwo.anders.com Feuerstein|Wilma|wilma@irgendwo.com Geröllheimer|Barney|barney@irgendwo.anders.com
Jetzt wollen wir die Datei in eine LoL einlesen, sortieren, wie oben beschrieben und ausgeben:
1: #!/usr/bin/perl -w 2: 3: use strict; 4: 5: my (@LoL, $array_ref, @sortetLoL, $i, $j); 6: my $file = "adress.dat"; 7: 8: open (FILE, "<$file") 9: || die "Kann File $file nicht öffnen: $!"; # File zum Lesen öffnen 10: 11: while (<FILE>) { 12: chomp; # einlesen und Zeilenvorschub entfernen 13: push @LoL, [ split /\|/ ]; # an | auftrennen und an LoL anhängen 14: } 15: 16: close (FILE) || die "Kann File $file nicht schließen: $!"; 17: 18: @sortetLoL = sort { $a->[0] cmp $b->[0] # Name 19: || 20: $a->[1] cmp $b->[1] # Vorname 21: } @LoL; 22: 23: for $i ( 0 .. $#sortetLoL ) { 24: for $j ( 0 .. $#{$sortetLoL[$i]} ) { 25: print "$sortetLoL[$i]->[$j]\t\t"; 26: } 27: print "\n" 28: }
Interessant ist hier das Sortieren in den Zeilen 18 bis 21. $a
und $b
sind eigentlich Referenzen auf das zu sortierende Array.
Damit ist $a->[0]
eine Referenz auf des erste Element einer Zeile
in der Liste von Listen.
Feuerstein Fred fred@irgendwo.com Feuerstein Wilma wilma@irgendwo.com Geröllheimer Barney barney@irgendwo.anders.com Geröllheimer Betty betty@irgendwo.anders.com
Literaturhinweise:
- perldoc perlref
- perldoc perldsc
- perldoc perllol
Zurück zum Anfang dieses Projekts.