Musterlösung 7 12.12.2003 Spielerstatistik In der Datei vfb.txt finden Sie eine Tabelle mit Informationen zu Spielern des VFB Stuttgart. Die einzelnen Spalten sind jeweils mit Tabulator getrennt. Einlesen der Datei Lesen Sie die Datei ein, indem Sie sie über ein Dateihandle öffnen. open (VFB, "vfb.txt") or die "Kann Datei nicht oeffnen: $!"; chomp($in); Die Spalten beinhalten folgende Information: Nr. Name Spiele Aus Ein Minuten Tore Geburtsdatum Kommentar: Die Datei ist nicht ganz sauber formatiert! Leerzeilen führen zu Warnungen, z.b. Use of uninitialized value in... daher: if ($in! / s*$/) { # Leerzeilen löschen unnötige Leerzeichen (Entfernung ist reine Kosmetik) am Zeilenende $in = s/ +$//g; innerhalb der Zeile $in = s/ * t */ t/g; Auslesen der Information in ein Array @line = split (/ t/, $in); Subroutine Lebensalter Schreiben Sie eine Subroutine, die für jeden Spieler das aktuelle Lebensalter berechnet, z.b. Timo Wenzel wurde am 30.11.1977 geboren und ist jetzt 26 Jahre alt.
Eine einfache Lösung ($alter) = &jahre ($line[7]); # Aufruf der Subroutine jahre() # Ausgabe: print "$line[1] wurde am $line[7] geboren und ist $alter Jahre alt.\n";... sub jahre { my $datum = shift @_; if ($datum){ # Definition der Subroutine # Auslesen des übergebenen Arguments # Kontrolle, ob definiert if ($datum =~ /(\d+)\.(\d+).(\d+)/){ # Jahr herausfinden my $spieler_jahr = $3; my $spieler_alter = 2003 - $spieler_jahr; # Lebensalter ermitteln return ($spieler_alter); # Rückgabe Ein komplexere Lösung aktuelles Datum Hier wird das jeweils aktuellen Datum berücksichtigt. ############################################### # Auslesen des aktuellen Datums aus localtime (unter Verwendung von # use locale ). Die meisten Angaben sind für uns redundant. my ($sek, # Durch my werden Warnungen wegen einmaliger Verwendung $min, # der Variablen unterdrückt $stunde, $tag, $monat, $jahr, $wochentag, $tag_im_jahr, $ist_sommerzeit) = localtime; $monat = $monat+1; $jahr = $jahr + 1900; ####################################### # Lebensalter ausgeben ($alter,$zusatz) = &jahre ($line[7]); if ($alter) { print "$spieler ist am $line[7] geboren und $alter Jahre alt.\n"; if ($zusatz) { print "$zusatz\n"; Perl, Zinsmeister 2 Lösung 7
######################################## # Definition der Subroutine jahre() sub jahre { my $datum = shift @_; my $geburtstag =""; # wird nur gefuellt, wenn Spieler Geburtstag hat if ($datum) { # zur Kontrolle if ($datum =~ /(\d+)\.(\d+).(\d+)/) { my $spieler_tag = $1; my $spieler_monat = $2; my $spieler_jahr = $3; my $spieler_alter =0; # Es wird getestet, ob der Spieler in diesem Jahr schon Geburtstag # gehabt hat # - ob die Monatsnummer des Spielers kleiner ist # als die aktuelle Monatsnummer. # - wenn die Monatsnummern gleich sind, werden die Tage analog # überprüft # - ggf. wird der String $geburtstag gefüllt # - anderfalls wird der Spieler erst noch Geburtstag haben # Falls Spieler schon Geburtstag hatte, d.h spieler_monat < Monat if ($spieler_monat < $monat) { $spieler_alter = $jahr - $spieler_jahr; # bzw. $spieler_tag < $tag elsif ($spieler_monat == $monat) { if ($spieler_tag < $tag) { $spieler_alter = $jahr - $spieler_jahr; # Sonderfall: Geburtstag! elsif ( $spieler_tag == $tag) { $spieler_alter = $jahr - $spieler_jahr; $geburtstag = "$spieler hat heute Geburtstag!\n"; # Andernfalls wird der Spieler erst noch Geburtstag haben Perl, Zinsmeister 3 Lösung 7
else { $spieler_alter = $jahr - $spieler_jahr -1; else { $spieler_alter = $jahr - $spieler_jahr -1; return ($spieler_alter, $geburtstag); Subroutine Durschnitt Berechnen Sie zusätzlich das Durchschnittsalter aller Spieler. Hier eine neutrale Lösung, die alle Werte in einem Array erwartet und davon den Durchschnittswert ausgibt. In der Ausgabe wird auf eine Stelle nach dem Komma gerundet. Hier wird eine neutrale Lösung vorgeschlagen, die als Argument ein Array mit numerischen Werten einliest und deren Durschnittswert zurückgibt. Es werden zwei Ausgabealternativen vorgestellt. Die komplexere testet auf die Anzahl der Namen, die dem maximalen Wert zugeordnet sind und passt entsprechend die Grammatik der Ausgabe an. # Durchschnittsalter: $alter_durchschnitt = & durchschnitt(@aller_alter); print "\ndas Durchschnittsalter der Spieler beträgt "; printf"%3.1f Jahre.\n", $alter_durchschnitt; # formatierte, # gerundete Ausgabe... ########################################### # Definition der Subroutine durchschnitt() sub durchschnitt { my $summe = 0; my $nenner = 0; foreach $x (@_){ $summe += $x; $nenner++; my $durchschnittswert = $summe/$nenner; return ($durchschnittswert); Perl, Zinsmeister 4 Lösung 7
Subroutine benanntes Maximum Als Zusatzaufgabe: Ermitteln Sie den Torschützenkönig, ebenfalls über eine Subroutine. Hier wird wieder eine neutrale Lösung vorgestellt. Diesmal wird ein Hash als Argument in der Subroutine verarbeitet und ein Array als Rückgabewert weitergegeben. # in der while-schleife des Hauptprogramms: # while ($in=<vfb>) { #... # Torstatistik: Belegen des Hashes mit Paaren Spieler/Tore $spieler = $line[1]; $tore = $line[6]; $torstatistik{$spieler=$tore; # kuerzer: # $torstatistik{$line[1]= $line [6] ########################## # Nach Beenden der while-schleife # Aufruf der Subroutine tore_maximum() @tore_maximum = &benanntes_maximum(%torstatistik); # Auslesen des Maximalwerts (= letztes Arrayelement) $max_tore = pop (@tore_maximum); ###################### # Einfache Ausgabe: print "Torschützekönig(e) mit $max_tore Toren:\n"; foreach $koenig (@tore_maximum){ print "$koenig\t"; print"\n"; ############################ # Defintion der Subroutine sub benanntes_maximum { # Auch fuer nicht ganzahlige Werte my %hash = @_; # Als Argument wird ein Hash mit # numerischen Werten uebergeben, # von denen das Maximum bestimmt # werden soll my $max = 0; my @array = (); # Anlegen lokaler Variablen Perl, Zinsmeister 5 Lösung 7
# effizientes Auslesen des Hashes while (($key,$numerischer_value) = each %hash) { # Bestimmen der maximalen Anzahl if ($numerischer_value >= $max){ $max = $numerischer_value; push (@{$array{$max, $key); # sammle Namen der jeweils # maximalen Anzahl in einem Array, # das als Wert jeweils Arrays aufbaut push (@{$array{$max, $max); # Ergaenze als letzten Eintrag im Array # des maximalen HashKey-Wertes # den numerischen Wert return (@{$array{$max); # Rückgabe: Achtung: wird flache Liste! ################## # Komplexe Ausgabe $first = shift (@tore_maximum); print "$first"; if (scalar (@tore_maximum) >1) { foreach $x (@tore_maximum) { print ", $x"; elsif (scalar (@tore_maximum) >0){ foreach $x (@tore_maximum) { print " und $x"; print " sind Torschützenkönige"; else{ print " ist Torschützenkönig"; print " mit $max_tore Toren.\n"; # erster und ggf. einziger Name # Ausgabe ohne und oder Komma # weitere Namen mit Komma # letzter Name mit und # die Pluralvariante # die Singularvariante Perl, Zinsmeister 6 Lösung 7
Ergebnis Timo Hildebrand (T) ist am 05.04.1979 geboren und 24 Jahre alt. Andreas Hinkel ist am 26.03.1982 geboren und 21 Jahre alt. Timo Wenzel ist am 30.11.1977 geboren und 26 Jahre alt. Marcelo José Bordon ist am 07.01.1976 geboren und 27 Jahre alt. Fernando Meira ist am 05.06.1978 geboren und 25 Jahre alt. Silvio MeiSSner ist am 19.01.1973 geboren und 30 Jahre alt. Jurica Vranjes ist am 30.01.1980 geboren und 23 Jahre alt. Ioannis Amanatidis ist am 03.12.1981 geboren und 22 Jahre alt. Heiko Gerber ist am 11.07.1972 geboren und 31 Jahre alt. Christian Tiffert ist am 18.02.1982 geboren und 21 Jahre alt. Emanuel Centurión ist am 25.08.1982 geboren und 21 Jahre alt. Alexander Hleb ist am 01.05.1981 geboren und 22 Jahre alt. Horst Heldt ist am 09.12.1969 geboren und 34 Jahre alt. Horst Heldt hat heute Geburtstag! Imre Szabics ist am 22.03.1981 geboren und 22 Jahre alt. Zvonimir Soldo ist am 22.03.1981 geboren und 22 Jahre alt. Philipp Lahm ist am 11.11.1983 geboren und 20 Jahre alt. Kevin Kuranyi ist am 02.03.1982 geboren und 21 Jahre alt. Markus Husterer ist am 16.06.1983 geboren und 20 Jahre alt. Serge Branco ist am 11.10.1980 geboren und 23 Jahre alt. Das Durchschnittsalter der Spieler beträgt 23.9 Jahre. Imre Szabics und Kevin Kuranyi sind Torschützenkönige mit 5 Toren. Perl, Zinsmeister 7 Lösung 7
Die einfache Programmalternative im Ganzen #! /usr/local/bin/perl -w use locale; # Oeffnen der Datei open (VFB, "../Material/vfb.txt") or die "Kann Datei nicht oeffnen: $!"; # Auslesen des aktuellen Datums aus localtime (unter Verwendung von # use locale ). Die meisten Angaben sind für uns redundant. my ($sek, # Durch my werden Warnungen wegen einmaliger Verwendung $min, # der Variablen unterdrückt $stunde, $tag, $monat, $jahr, $wochentag, $tag_im_jahr, $ist_sommerzeit) = localtime; $monat = $monat+1; $jahr = $jahr + 1900; # Einlesen der Datei ueber Dateihandle while ($in=<vfb>) { chomp($in); # Auslesen der Information in ein Array @line = split (/\t/, $in); # Aufruf der Subroutine jahre() $alter = &jahre ($line[7]); if ($alter){ print "$line[1] wurde am $line[7] geboren und ist $alter Jahre alt.\n"; close (VFB); # Durchschnittsalter: $alter_durchschnitt = &durchschnitt(@aller_alter); # Aufruf der Subroutine print "\ndas Durchschnittsalter der Spieler beträgt "; printf"%3.1f Jahre.\n", $alter_durchschnitt; # formatierte, # gerundete Ausgabe Perl, Zinsmeister 8 Lösung 7
################################### # Definition der Subroutine jahre() sub jahre { my $datum = shift @_; # Auslesen des übergebenen Arguments if ($datum){ # Kontrolle, ob definiert if ($datum =~ /(\d+)\.(\d+).(\d+)/){ # Jahr herausfinden my $spieler_jahr = $3; my $spieler_alter = 2003 - $spieler_jahr; return ($spieler_alter); # Rückgabe ########################################### # Definition der Subroutine durchschnitt() sub durchschnitt { my $summe = 0; # lokale Variablen my $nenner = 0; foreach $x (@_){ $summe += $x; $nenner++; # Jeder Arraywert wird # ausgewertet my $durchschnittswert = $summe/$nenner; return ($durchschnittswert); # Rückgabe Perl, Zinsmeister 9 Lösung 7
Die komplexere Programmalternative im Ganzen #! /usr/local/bin/perl -w use locale; ################### # Oeffnen der Datei open (VFB, "../Material/vfb.txt") or die "Kann Datei nicht oeffnen: $!"; ############################### # Auslesen des aktuellen Datums aus localtime (unter Verwendung von # use locale ). Die meisten Angaben sind für uns redundant. my ($sek,$min,$stunde,$tag,$monat,$jahr,$wochentag,$tag_im_jahr,$ist_sommerzeit) = localtime; $tag = 9; $monat = $monat+1; $jahr = $jahr + 1900; ###################################### # Einlesen der Datei ueber Dateihandle while ($in=<vfb>) { chomp($in); if ($in!~ /^\s*$/) { $in =~ s/ +$//g; $in =~ s/ *\t */\t/g; # Leerzeilen ausschliessen! # Leerzeichen am Zeilenende loeschen # Formatierung verbessern @line = split (/\t/, $in); # Auslesen der Inormation ############### # Torstatistik: Belegen des Hashes mit Paaren Spieler/Tore $spieler = $line[1]; $tore = $line[6]; $torstatistik{$spieler=$tore; # kuerzer: # $torstatistik{$line[1]= $line [6] ############################# # Berechnung des Lebensalters ($alter,$zusatz) = &jahre ($line[7]); # Aufruf der Subroutine jahre() Perl, Zinsmeister 10 Lösung 7
if ($alter) { print "$spieler ist am $line[7] geboren und $alter Jahre alt.\n"; push( @aller_alter,$alter); if ($zusatz) { print "$zusatz\n"; # Bei Geburtstag Ausgabe # des Zusatzes ############################# # Schliessen des Dateihandles close (VFB); ################################### # Berechnen des Durchschnittsalters $alter_durchschnitt = &durchschnitt(@aller_alter); # Aufruf der # Subroutine durchschnitt() print "\ndas Durchschnittsalter der Spieler beträgt "; printf"%3.1f Jahre.\n", $alter_durchschnitt; # formatierte, # gerundete Ausgabe ###################################### # Bestimmung des Torschuetzenkoenigs @tore_maximum = &benanntes_maximum(%torstatistik); # Aufruf der # Subroutine tore_maximum() $max_tore = pop (@tore_maximum); # Auslesen des Maximalwerts # (= letztes Arrayelement) ################## # Komplexe Ausgabe $first = shift (@tore_maximum); print "$first"; if (scalar (@tore_maximum) >1) { foreach $x (@tore_maximum) { print ", $x"; elsif (scalar (@tore_maximum) >0){ # erster und ggf. einziger Name # Ausgabe ohne und oder Komma # weitere Namen mit Komma Perl, Zinsmeister 11 Lösung 7
foreach $x (@tore_maximum) { print " und $x"; print " sind Torschützenkönige"; else{ print " ist Torschützenkönig"; print " mit $max_tore Toren.\n"; # letzter Name mit und # die Pluralvariante # die Singularvariante #################################### # Definition der Subroutine jahre() sub jahre { my $datum = shift @_; my $geburtstag =""; # wird nur gefuellt, wenn Spieler Geburtstag hat if ($datum) { if ($datum =~ /(\d{2)\.(\d{2).(\d{4)/) { my $spieler_tag = $1; my $spieler_monat = $2; my $spieler_jahr = $3; my $spieler_alter =0; # Falls Spieler schon Geburtstag hatte, d.h spieler_monat < Monat if ($spieler_monat < $monat) { $spieler_alter = $jahr - $spieler_jahr; # bzw. $spieler_tag < $tag elsif ($spieler_monat == $monat) { if ($spieler_tag < $tag) { $spieler_alter = $jahr - $spieler_jahr; # Sonderfall: Geburtstag! elsif ( $spieler_tag == $tag) { $spieler_alter = $jahr - $spieler_jahr; $geburtstag = "$spieler hat heute Geburtstag!\n"; # Andernfalls wird der Spieler erst noch Geburtstag haben Perl, Zinsmeister 12 Lösung 7
else { $spieler_alter = $jahr - $spieler_jahr -1; else { $spieler_alter = $jahr - $spieler_jahr -1; return ($spieler_alter, $geburtstag); ########################################### # Definition der Subroutine durchschnitt() sub durchschnitt { my $summe = 0; # lokale Variablen my $nenner = 0; foreach $x (@_){ $summe += $x; $nenner++; # Jeder Arraywert wird # ausgewertet my $durchschnittswert = $summe/$nenner; return ($durchschnittswert); # Rückgabe ############################################## # Definition der Subroutine benanntes_maximum() sub benanntes_maximum { # Auch fuer nicht ganzahlige Werte my %hash = @_; # Als Argument wird ein Hash mit # numerischen Werten uebergeben, # von denen das Maximum bestimmt # werden soll my $max = 0; my @array = (); # Anlegen lokaler Variablen # effizientes Auslesen des Hashes while (($key,$numerischer_value) = each %hash) { # Bestimmen der maximalen Anzahl if ($numerischer_value >= $max){ $max = $numerischer_value; Perl, Zinsmeister 13 Lösung 7
push (@{$array{$max, $key); push (@{$array{$max, $max); # sammle Namen der jeweils # maximalen Anzahl in einem Array, # das als Wert jeweils Arrays aufbaut # Ergaenze als letzten Eintrag im Array # des maximalen HashKey-Wertes # den numerischen Wert return (@{$array{$max); # Rückgabe: Achtung: wird flache Liste! Perl, Zinsmeister 14 Lösung 7