Perls Reportgenerator
Was ist ein Reportgenerator?
Ein Reportgenerator ist eine Funktion oder ein Programm, das zur Erstellung von Reports dient.
Mit Perl werden Reports mit Hilfe eines bestimmten Befehls definiert und ausgeführt.
Was ist ein Report?
Ein Report ist ein mit einem Programm, dem Reportgenerator, erstellte formatierte Ausgabe - sozusagen ein Bericht.
Reports können zum Beispiel Listen von Mitarbeitern, von Benutzern auf einem Computer oder sonstwas sein.
Wie erstelle ich einen Report mit Perl?
Um einen Report zu erstellen, muss festgelegt werden, wie die Ausgabe formatiert wird, wohin die Ausgabe geht und was ausgegeben wird.
Mit dem Befehl
format wird ein Ausgabeformat für den Report definiert und über den Befehl
write gestartet.
format ist wie folgt aufgebaut:
format AUSGABEZIEL =
FORMAT1
FORMAT2
FORMAT3
...
FORMATN
.
AUSGABEZIEL ist der Name des Formats und des Dateihandles, kann also eine geöffnete Datei oder auch eben STDOUT, die Standardausgabe sein. Je nach Wunsch und Zweck.
FORMAT1 bis FORMATN sind der Formatstring, also Zeichenketten, in denen spezielle Zeichen die Position und die Breite der Ausgabe steuern. Mit diesen speziellen Zeichen werden sozusagen die Spalten der Ausgabe definiert.
Der Punkt am Zeilenanfang beendet den Formatstring.
Damit es nicht alles so theoretisch abläuft, folgt gleich ein kleines, praxisfernes aber lehrreiches Beispiel.
Aufgabe: Schreibe einen Report, der das heutige Datum ausgibt mit dem dazugehörigen Alter der Drachin
GwenDragon? und einem Spruch des Tages.
Ich würde es so lösen:
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $datum = sprintf( "%02d.%02d.%04d", $wday, $mon + 1, $year + 1900);
my $gebjahr = 577; # Geburtsjahr der Drachin ;)
my $name = "GwenDragon";
my $alter = 1900 + $year - $gebjahr;
sub Spruch1() {
return <<'TXT';
C ist toll.
C++ ist toller.
C# ist Igitter.
Perl ist perliger als C. ;)
Aber Drerl ist GwenDragons Perl.
Perl++ || die;
*FAUCH*
TXT
}
format STDOUT =
Heute ist der @<<<<<<<<<<
$datum
Guten Tag, @<<<<<<<<<<. Du bist jetzt schon @<<<< Jahre alt!
$name,$alter
Dein Spruch des Tages ist:
-------------------------
^*
&Spruch1()
-------------------------
.
write;
Wie formatiere ich die Ausgabe?
Die Ausgabe wird durch die Festlegung des Formatstrings gesteuert.
Dabei gibt es bestimmte Zeichen, welche die Ausrichtung steuern und an welcher Position die auszugebenden Werte stehen und wie breit die Spalten sind.
Perl stellt zudem noch bestimmte Variablen zu Verfügung, mit denen zum Beispiel die Seitennummer oder die Anzahl der Zeilen in einem Report ausgegeben werden können.
Außerdem kann ein Format für Kopf und Fuß eines Reports festgelegt werden.
Ein Beispiel für den Kopfteil:
format STDOUT_TOP =
----------------------------------------------------------------------------
Angemeldete Benutzer auf Computer @<<<<<<<<<<<<<< am @<<<<<<<<<<
----------------------------------------------------------------------------
$comp,$datum
Name Login Abteilung User-ID
----------------------------------------------------------------------------
.
Erklärung: Der Report wird an die Standardausgabe geschrieben und ist (zu sehen durch die Anfügung von _TOP an den Formatnamen) ein Report-Kopf.
Die Ausgabe von Werten erfolgt an der Stelle der @-Zeichen. Die Anzahl der Zeichen nach dem @ bestimmt die Breite der Ausgabe.
Die Variablen $comp und $datum werden in der Reihenfolge des Auftretens des @ ausgegeben.
Der Punkt am Zeilenanfang definiert das Ende der Formatdefinition.
Ein Beispiel für den Report:
format STDOUT =
@<<<<<<<<<<<<<<<<<< @||||||| @<<<<<<<<<< @>>>>>>>
$name, $login, $office, $uid
.
Erklärung: Es werden die Werte der folgenden Variablen an der Stelle des @ ausgegeben.
$name linksbündig, $login zentriert, $office linksbündig, $uid rechtsbündig.
Die Variablen sind nur zur besseren Zuordnung zum Format unter dem @ angeordnet. Das ist nicht notwendig, erleichtert aber die Arbeit.
Ein Beispiel für den Fuß:
format STDOUT_BOTTOM =
Seite @|||
$%
.
Erklärung: Ein Fußteil wird durch das Anhängen von _BOTTOM an die Formatbezeichnung gekennzeichnet.
Im Fuß des Reports wird das Wort Seite mit der zentrierten Ausgabe der Seitennummer an die Standardausgabe ausgegeben. Derzeit ist es noch nicht automatisch möglich den Fußteil auszugeben, siehe z.B.
Footers format, footer footer. Daher ist hier ein wenig Handarbeit notwendig. Eine mögliche Lösung wäre folgende Zeilen in den Code, der die Ausgabe erzeugt einzubauen:
#Fusszeile(n) am Seitenende Ausgeben
if ($- <= 3 && $- > 0) { # die hier verwendete "3" entspricht der Zeilenanzahl des Fuß
$~ = STDOUT_BOTTOM; # verwendetes Format auf "Fuß" umstellen
write; # Seitenfuß ausgeben
$~ = STDOUT; # Format auf "STDOUT" zurücksetzen
$-=0; # Anzahl der verbleibenden Zeilen auf dieser Seite auf 0 setzen,
# damit werden die nächsten Daten incl. Kopf auf der nächsten
# Seite ausgegeben
}
#Ausgabe der "Datenzeile"
write;
Wenn der Report Mehrzeilige Daten enthält, sollte die hier verwendete "3" höher angesetzt werden. Hier muss ein Wert gewählt werden der den "Anzahl der Fußzeilen" + "der Maximalen Zeilenanzahl eines Datensatzes" - 1 entspricht. Damit kann es zwar sein, das einige Zeilen am Seitenende verschenkt werden, aber es wird auf jeder Seite ein Seitenfuß gedruckt.
Welche Steuerzeichen gibt es?
Wie wir schon gesehen haben, steuert
format die Position der ausgegebenen Variablen mit bestimmten Zeichen.
Die Ausgabe eines Wertes erfolgt an der Stelle des @ oder des ^. Das ^ dient zur Ausgabe von Werten, die mehrzeilig sind.
Achtung: Wenn mehrzeilige Werte in einem Report enthalten sein sollen, müssen
alle Felder als Mehrzeilig definiert werden, auch wenn nur eines wirklich Mehrzeilig ist!
Diese Zeichen definieren also die Spalten.
Nachfolgende Zeichen steuern die Ausrichtung zum @ bzw. ^ selbst:
- < linksbündig
- | zentriert
- > rechtsbündig
Die Anzahl nachfolgenden Zeichen bestimmt die Breite der jeweiligen Spalte.
Ein ~ am Zeilenanfang unterdrückt Leerzeilen bei der Ausgabe einer Variablen.
Außerdem gibt es die Möglichkeit mit # und . (englisches Format!) Zahlen im numerischen Format auszugeben.
Wie kann ich das @ selbst ausgeben?
Das @ muß dabei in Anführungszeichen stehen, dann verliert es die Bedeutung der Positionsplatzhalters.
Kann ich einen Kommentar in den Formatstring schreiben?
Ja, das geschieht mit einem # am Anfang der Zeile.
Welche speziellen Variablen gibt es?
Perl selbst stellt bestimmte Sondervariablen zur Verfügung, die in
format benutzt werden können und die Ausgabe steuern.
- $~ ($FORMAT_NAME) beinhaltet den Namen des aktuellen Formats.
- $^ ($FORMAT_TOP_NAME) den Namen des Kopfs des aktuellen Formats.
- $% ($FORMAT_PAGE_NUMBER) die saktuelle Seitennummer
- $= ($FORMAT_LINES_PER_PAGE) die Anzahl der Zeilen auf der Seite.
- $| ($OUTPUT_AUTOFLUSH) die Pufferung der Ausgabe.
- $^L ($FORMAT_FORMFEED) vor jedem Seitenanfang (außer der ersten)
All diese Variablen werden immer auf Basis des aktuellen Dateihandles gesetzt.
Kann ich den Formatstring auch selbst erzeugen?
Es gibt Situationen, in denen reicht es nicht,
format fest definiert zu kodieren.
Das ist aber kein Problem, da wie bei jedem Perl-Code die Definition in eine Zeichenkette geschrieben werden kann, die wiederum mit
eval ausgewertet wird.
my %vars = (
Var1 => 4.22001,
Var2 => 9.3334431,
Var3 => -1,
Var9 => 99
);
my $fstring = ''; # Format für Variablen
my $valstring = ''; # Variablenwerte
foreach my $k ( sort keys %vars ) {
$fstring .= '@' . '<' x length( "$vars{$k}" ) . ' '; # Format definieren
$valstring .= '$vars{' . $k. '},'; # Variablen eintragen
}
chop($valstring); # Überflüsseiges Komma am Ende wieder entfernen
chop($fstring); # Überflüsseiges Leerzeichen am Ende wieder entfernen
my $reportcode = <<"FS";
format STDOUT =
Ausgabe der Variablen
--------------------------------------------
$fstring
$valstring
--------------------------------------------
.
write; # Ausgabe des Reports!
FS
eval ( $reportcode );
die ("Report: Problem mit Format!") if $@;
Wie schreibe ich den Report in eine Datei?
Wie schon erwähnt erfolgt die Ausgabe des Reports an ein Dateihandle.
Das bedeutet, dass Ausgaben auch in Dateien oder Pipes erfolgen können.
Ein Beispiel, in dem erst ein Report an die Standardausgabe und dann in die Datei Report.txt geschrieben wird.
my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
my $datum = sprintf( "%02d.%02d.%04d", $wday, $mon + 1, $year + 1900);
my $gebjahr = 577; # Geburtsjahr der Drachin ;)
my $name = "GwenDragon";
my $alter = 1900 + $year - $gebjahr;
sub Spruch() {
return <<'TXT';
Spieglein, Spieglein an der Wand.
Welches ist die Schönste im ganzen Land?
Perl++ || die;
*FAUCH*
TXT
}
format STDOUT =
Heute ist der @<<<<<<<<<<
$datum
Guten Tag, @<<<<<<<<<<. Du bist jetzt schon @<<<< Jahre alt!
$name, $alter
Dein Spruch des Tages ist:
-------------------------
^*
&Spruch()
-------------------------
.
open (FH, "> report.txt") or die($?); # Datei öffnen
select(FH); # STDOUT > Datei
$| = 1; # Pufferung abschalten
$~ = "STDOUT"; #Ausgabeformat für report.txt setzen
write; # Report schreiben
close(FH) or die("$?"); # Datei schließen
Fallen beim Arbeiten mit Reports
1. Der einzelne Punkt am Zeilenanfang kann eine E-Mail beenden, wenn ein falsch konfigurierter E-Mailer wie sendmail oder ähnliche benutzt wird, um Code zu versenden, in dem ein Formatstring für Reports steckt.
Eine Abhilfe schafft das Einrücken des Teiles des E-Mailtextes, das den Code enthält.
2. Lexikalische Variablen (mit my deklariert) sind in
format unsichtbar solange
format sich nicht im Bereich (Block) der lexikalischen Variable selbst befindet.
3. Formate benutzen die locale Einstellung des Programms!
Wenn die Umgebung LC_NUMERIC definiert, wird diese benutzt, um den Dezimalpunkt für eine numerische Ausgabe zu verwenden.
Formatierte Ausgaben können nicht durch ein
use locale
kontolliert werden, da das Pragma an den Block des Programms gebunden ist, aber Formate außerhalb dieses Blicks existieren.
Weiteres bitte in der perldoc unter perllocale nachsehen.
4. Innerhalb eines Ausdrucks werden Whitespace-Zeichen wie \n, \t und \f wie ein Leerzeichen behandelt. Deswegen sollte auf jede Variable in einem Format folgender Code vorher angewandt werden:
$value =~ tr/\n\t\f/ /;
Weiteres
Weiteres findet sich in der Perldoc unter
perldoc perlform
--
GwenDragon - 12 Nov 2005
Ergänzungen, Kommentare
--
RolandS - 24 Mar 2006 ,Ausgabe des Fuß weiter beschrieben, und Mehrzeilen Output ergänzt
--
ChristophBacher - 07 Sep 2009, zwei verbatim-Endtags korrigiert im letzten Abschnitt