Hallo, ich beschäftige mich schon das ganze Wochenende mit einem Problem und hoffe, dass ich durch diese Liste den richtigen Input bekomme. Ich muss eine Liste mit Kundendatensätzen parsen, die von einer externen Quelle kommen und mir im Textformat als Datei vorliegen. Diese Daten sehen (gekürzt) wie folgt aus (fiktiver Auszug): ---Kundendatensätze--- Kdnr: 1211 Name: Schmitz, Peter Firma: Schmitz GmbH Beschreibung: Projekt XY, Netzwerkverkabelung Telefon: 0123 45678 Zusatz: Kunde will Angebot für VPN ---Kundendatensätze--- Diese Datensätze möchte ich einlesen und in eine HTML-Tabelle schreiben. Das Problem dabei ist, dass ich (ausser Kdnr) nicht weiß, wie viele Elemente in einem Datensatz enthalten sind, da die Daten leider nicht vollständig sind, d.h. ich weiß, dass mit Kdnr ein Datensatz beginnt und sobald das nächste Mal "Kdnr" vorkommt, bereits ein neuer Datensatz begonnen hat, wobei die maximale Anzahl an Feldern je Datensatz neun ist (dann muss spätestens der nächste Kunde kommen, kann aber auch vorher sein). Einige Felder können auch mehrfach vorhanden sein bzw. sich über mehrere Zeilen erstrecken, wie das folgende (fiktive Negativ-) Beispiel zeigt: ---Kundendatensätze--- Kdnr: 1219 Name: Müller, Franz Firma: Müller & Söhne GbR Beschreibung: Projekt AB, Datensicherung Beschreibung: Datensicherung Windows NT-Server Telefon: 0123 45678 ---Kundendatensätze--- In diesem Beispiel fehlt z.B. das Zusatzfeld, aber dafür sind zwei Beschreibungen enthalten. Später in der HTML-Tabelle soll jedes Feld in einer jeweils eigenen Spalte stehen. Erstreckt sich ein Feld (wie hier Beschreibung) über zwei Zeilen, soll es in einer Spalte stehen (also praktisch zusammenfassen). Wie kann ich dieses Problem am besten mit Perl lösen? Ich habe bisher folgenden Quellcode entwickelt, der gekürzt und auf fünf Felder vereinfacht so ausschaut: #!/usr/bin/perl open(DATEI, $ARGV[0]) || die "Konnte Eingabedatei nicht oeffnen!\n"; @Zeilen=<DATEI>; close(DATEI); print "<table width='100%' border='1'>\n"; print "<tr>\n"; print "<th>Kdnr:</th>\n"; print "<th>Name:</th>\n"; print "<th>Firma:</th>\n"; print "<th>Beschreibung:</th>\n"; print "<th>Telefon:</th>\n"; print "<th>Zusatz:</th>\n"; print "</tr>\n"; foreach $zeile (@Zeilen) { if ($zeile =~ /^.*Kdnr: (.*)$/) { push @ausgabe,$zeile; } if ($zeile =~ /^.*Name: (.*)$/) { push @ausgabe,$zeile; } if ($zeile =~ /^.*Firma: (.*)$/) { push @ausgabe,$zeile; } if ($zeile =~ /^.*Beschreibung: (.*)$/) { push @ausgabe,$zeile; } if ($zeile =~ /^.*Telefon: (.*)$/) { push @ausgabe,$zeile; } if ($zeile =~ /^.*Zusatz: (.*)$/) { push @ausgabe,$zeile; } } print "<tr>"; foreach $ergebnis (@ausgabe) { $ergebnis =~ s/Kdnr: //sgi; $ergebnis =~ s/Name: //sgi; $ergebnis =~ s/Firma: //sgi; $ergebnis =~ s/Beschreibung: //sgi; $ergebnis =~ s/Telefon: //sgi; $ergebnis =~ s/Zusatz: //sgi; # Neuer Datensatz beginnt if ($ergebnis =~ /^.*Kdnr: (.*)$/) { print "</tr><tr>"; } print "<td>$ergebnis</td>"; } print "</tr>\n"; print "</table>\n"; Das Problem an diesem Quellcode ist, dass der natürlich nicht "erkennen" kann, wenn ein Feld in einem Datensatz fehlt und übersprungen oder z.B. mit "unbekannt" gekennzeichnet werden müsste. Wie könnte ich dieses implementieren bzw. hat jemand ne ganz andere Vorgehensweise? Eine Möglichkeit wäre auch, erst alle Werte einzulesen und wenn der erkennt, dass bereits der nächste Datensatz angefangen hat, alles ausgibt. Hier ist natürlich das Problem, dass beim allerersten Datensatz die Werte der darauffolgenden Zeilen bzw. Felder noch nicht bekannt sind... Ich freue mich auf (hoffentlich reichlich) Antworten :-) Vielen Dank und schöne (sonnige) Grüße, Werner.
Halloechen
Ich freue mich auf (hoffentlich reichlich) Antworten :-)
Mit Deinem Perl-Code kann ich nichts anfangen - ist mir zu kryptisch. Zum Prinzip, wie ich es machen wuerde: Lege Dir zuanfangs eines jeden Datensatzes ein assoziatives Array (in Perl Hash genannt?) an und lege fuer jeden moeglichen Schluessel einen Wert '' rein. Schluessel waeren bei Dir 'Kdnr', 'Name', 'Firma' etc. In Perl geht das glaube irgendwie so: $daten{'Kdnr'} = ''; ... (Aber Perl brauche ich jemanden, der so kryptischen Code schreibt, sicher nicht zu erklaeren) Dann parst Du aus jeder Zeile das Schluessel-Wert-Paar und haengst den Wert an den bestehenden an. ($key, $value) = split( ':', $line ); $daten{$key} .= $value; Das uebernimmt elegant das Problem der ueber mehrere Zeilen verteilten Daten. Bei Laune kannst Du auch noch Abfragen, ob es einen solchen Schluessel bereits gibt. Dadurch kannst Du ungueltige Schluessel ausfiltern. Praktisch: Alle Felder, die nicht aufgetreten sind, haben am Ende eines Eintrages den Wert ''. Die kannst Du so uebernehmen oder durch irgendetwas wie '-' oder 'unbekannt' ersetzen. Bye -- 1 Bodo Kaelberer 123 http://www.webkind.de/ 3 4 "A button I have made must be pushed." (ip)
On Son, 22 Jun 2003 at 14:40 (+0200), Bodo Kaelberer wrote: [...]
Zum Prinzip, wie ich es machen wuerde: Lege Dir zuanfangs eines jeden Datensatzes ein assoziatives Array (in Perl Hash genannt?) an und lege fuer jeden moeglichen Schluessel einen Wert '' rein. Schluessel waeren bei Dir 'Kdnr', 'Name', 'Firma' etc. In Perl geht das glaube irgendwie so:
$daten{'Kdnr'} = ''; ...
Im Prinzip ACK, aber s. u. [...]
Dann parst Du aus jeder Zeile das Schluessel-Wert-Paar und haengst den Wert an den bestehenden an.
($key, $value) = split( ':', $line ); $daten{$key} .= $value;
Das uebernimmt elegant das Problem der ueber mehrere Zeilen verteilten Daten. Bei Laune kannst Du auch noch Abfragen, ob es einen solchen Schluessel bereits gibt. Dadurch kannst Du ungueltige Schluessel ausfiltern.
Praktisch: Alle Felder, die nicht aufgetreten sind, haben am Ende eines Eintrages den Wert ''. Die kannst Du so uebernehmen oder durch irgendetwas wie '-' oder 'unbekannt' ersetzen.
Hm, etwas vage ;-) Als erstes ein Tipp: Du solltest immer mit use strict; arbeiten und Deine Variablen sauber deklarieren: my %daten = (); Du ersparst Dir viel Ärger und Fehlersuche damit. Und Du musst bei jedem neuen Datensatz (Also wenn Kdnr auftaucht) den Hash leeren, sonst sind spätestens beim 2. Durchlauf die Keys eben nicht mehr leer. Du kannst ihn nicht lokal in der Schleife deklarieren, weil Du ihn ja nicht bei jedem Durchlauf des foreach neu haben willst. Um die Spaltenanzahl konstant zu halten und nicht Spalten verrutschen zu lassen, empfiehlt sich ein zusätzliches Array: my @spalten = ("Kdnr", "Name", "Firma", "Beschreibung", "Telefon", "Zusatz"); So sollte es gehen: <schnipp> #! /usr/bin/perl use warnings; use strict; # Datei lesen die "usage: $0 Dateiname\n" unless defined $ARGV[0]; open DATEI, "$ARGV[0]" or die "Fehler beim Oeffnen der Datei ($!)\n"; my @zeilen = <DATEI>; close DATEI; # meine Variablen my %daten = (); # der Hash fuer die Werte und Keys eines Datensatzes my @spalten = ("Kdnr", "Name", "Firma", "Beschreibung", "Telefon", "Zusatz"); # Tabellenheader print "<table width='100%' border='1'>\n"; print "<tr>\n"; foreach (@spalten) { printf "<th>%s</th>\n", $_; } print "</tr>\n"; foreach (@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt chomp; # \n wegwerfen next if /^ *$/; # leere Zeilen wegschmeissen if (defined ($daten{'Kdnr'}) && /^Kdnr/) { # $_ faengt mit KdNr an print "<tr>\n"; # Tabellenzeile foreach my $out (@spalten) { # Spalten abklappern if (defined $daten{$out}) { # Key vorhanden? printf "<td>%s</td>\n", $daten{$out}; # Ja: Wert schreiben undef ($daten{$out}); # Hash-Key wegschmeissen } else { print "<td> </td>\n"; # Nein: Leerzeichen } } print "</tr>\n"; # Ende Tabellenzeile } my ($key, $value) = split /:/; # neue Zeile aufspalten $key =~ s/^ *(.*[^ ]) *$/$1/; # Leerzeichen am Anfang und Ende weg $value =~ s/^ *(.*[^ ]) *$/$1/; # dito if (defined $daten{$key}) { $daten{$key} .= ", " . $value; # Wert an Hash anhaengen } else { $daten{$key} = $value; # Hash-Key neu erzeugen } } # letzten Satz auch schreiben print "<tr>\n"; # Tabellenzeile foreach my $out (@spalten) { # Spalten abklappern if (defined $daten{$out}) { # Key vorhanden? printf "<td>%s</td>\n", $daten{$out}; # Ja: Wert schreiben } else { print "<td> </td>\n"; # Nein: Leerzeichen } } print "</tr>\n</table>\n"; # Ende Tabelle exit 0; <schnapp> Das Verhalten, wenn im Wert ein ":" auftaucht, muss noch gesondert abgehandelt werden, sowas habe ich hier weggelassen. Sauberer wäre es noch, die Ausgabe (die ja an 2 Stellen auftritt) in eine Funktion zu packen. Ach ja, wenn auch Tabs statt Leerzeichen auftreten können, sollte statt der " " in den Ersetzungen besser \s genommen werden. Jan
Hello, On Mon, 23 Jun 2003, Jan Trippler wrote:
# Datei lesen die "usage: $0 Dateiname\n" unless defined $ARGV[0]; open DATEI, "$ARGV[0]" or die "Fehler beim Oeffnen der Datei ($!)\n";
Die Datei sollte man IMO explizit "readonly" oeffnen...
my @zeilen = <DATEI>; close DATEI;
*AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA* Das ist der gleiche Fehler wie von grepmail. Versuch das mal mit ner Datei von ein paar 100 MB!!! Stehen lassen kann man das "open".
# meine Variablen my %daten = (); # der Hash fuer die Werte und Keys eines Datensatzes my @spalten = ("Kdnr", "Name", "Firma", "Beschreibung", "Telefon", "Zusatz");
# Tabellenheader print "<table width='100%' border='1'>\n"; print "<tr>\n"; foreach (@spalten) { printf "<th>%s</th>\n", $_; } print "</tr>\n";
foreach (@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt
*ARGH* Hier wird's dann wirklich doof, wenn man sowieso zeilenweise liest, kann man gleich die Datei hernehmen. while(<DATEI>) { # Zeilen abklappern, Zeile wird in $_ abgelegt (ja, der Kommentar stimmt so!)
chomp; # \n wegwerfen next if /^ *$/; # leere Zeilen wegschmeissen
Wuerde ich andersrum schreiben, bei leeren Zeilen faellt dann der ueberfluessige Aufruf von 'chomp' weg: next if /^\s*$/; # leere Zeilen wegschmeissen chomp; # \n wegwerfen
if (defined ($daten{'Kdnr'}) && /^Kdnr/) { # $_ faengt mit KdNr an print "<tr>\n"; # Tabellenzeile foreach my $out (@spalten) { # Spalten abklappern if (defined $daten{$out}) { # Key vorhanden? printf "<td>%s</td>\n", $daten{$out}; # Ja: Wert schreiben undef ($daten{$out}); # Hash-Key wegschmeissen
Ich wuerde eher jew. beim Auftauchen von 'Kdnr' das gesamte hash reinitialisieren: if (defined ($daten{'Kdnr'}) && /^Kdnr/) { # $_ faengt mit KdNr an print "<tr>\n"; # Tabellenzeile foreach my $out (@spalten) { # Spalten abklappern if (defined $daten{$out}) { # Key vorhanden? printf "<td>%s</td>\n", $daten{$out}; # Ja: Wert schreiben } else { print "<td> </td>\n"; # Nein: Leerzeichen } } print "</tr>\n"; # Ende Tabellenzeile %daten = (); # hash reinitialisieren } ## in $_ steht immer noch das neue Kdnr: ...
my ($key, $value) = split /:/; # neue Zeile aufspalten
Die Deklaration wuerde ich aus der Schleife rausnehmen, das ist nicht noetig. Also das 'my ($key, $value)' vor das while und dann hier nur noch: ($key, $value) = split /:/; # neue Zeile aufspalten
$key =~ s/^ *(.*[^ ]) *$/$1/; # Leerzeichen am Anfang und Ende weg
$key =~ s/^\s*(.*\S)\s*$/$1/;
$value =~ s/^ *(.*[^ ]) *$/$1/; # dito
$value =~ s/^\s*(.*\S)\s*$/$1/;
if (defined $daten{$key}) { $daten{$key} .= ", " . $value; # Wert an Hash anhaengen } else { $daten{$key} = $value; # Hash-Key neu erzeugen } }
Das sollte so weiter funktionieren. Hier ist man dann "durch", und es kann: close(DATEI); folgen.
# letzten Satz auch schreiben [Rest ok] <schnapp>
Das Verhalten, wenn im Wert ein ":" auftaucht, muss noch gesondert abgehandelt werden, sowas habe ich hier weggelassen.
($key, @rest) = split(':'); $value = join('', @rest); '@rest' dabei auch noch vor der Schleife deklarieren
Sauberer wäre es noch, die Ausgabe (die ja an 2 Stellen auftritt) in eine Funktion zu packen. Ach ja, wenn auch Tabs statt Leerzeichen auftreten können, sollte statt der " " in den Ersetzungen besser \s genommen werden.
Ja. s.o... Ich fasse nochmal zusammen: ==== ungetestet ==== #! /usr/bin/perl use warnings; use strict; # meine Variablen my %daten = (); # der Hash fuer die Werte und Keys eines Datensatzes my @spalten = ("Kdnr", "Name", "Firma", "Beschreibung", "Telefon", "Zusatz"); my ($key, $val, @rest); sub print_row() { print "<tr>\n"; # Tabellenzeile foreach my $out (@spalten) { # Spalten abklappern if (defined $daten{$out}) { # Key vorhanden? printf "<td>%s</td>\n", $daten{$out}; # Ja: Wert schreiben } else { print "<td> </td>\n"; # Nein: Leerzeichen } } print "</tr>\n"; # Ende Tabellenzeile } # Datei lesen die "usage: $0 Dateiname\n" unless defined $ARGV[0]; open(DATEI, "<$ARGV[0]") or die "Fehler beim Oeffnen der Datei: $!"; # Tabellenheader, ggfs. zum kompletten html-header erweitern print "<table width='100%' border='1'>\n"; print "<tr>\n"; foreach (@spalten) { printf "<th>%s</th>\n", $_; } print "</tr>\n"; while(<DATEI>) { # Zeilen abklappern, Zeile wird in $_ abgelegt next if /^\s*$/; # leere Zeilen wegschmeissen chomp; # \n wegwerfen if (defined ($daten{'Kdnr'}) && /^Kdnr/) { # $_ faengt mit KdNr an, # also ist der letzte Datensatz vollstaendig, also diesen # ausgeben... print_row(); # ... und den hash reinitialisieren %daten = (); } # aktuelle Zeile aufspalten... ($key, @rest) = split(':'); $val = join('', @rest); # ... saeubern ... $key =~ s/^\s*(.*\S)\s*$/$1/; # Leerzeichen am Anfang und Ende weg $val =~ s/^\s*(.*\S)\s*$/$1/; # dito # ... und bis zur Ausgabe via print_row bei naechsten Datensatz in # %daten speichern... if (defined $daten{$key}) { $daten{$key} .= ", " . $val; # Wert an Hash anhaengen } else { $daten{$key} = $val; # Hash-Key neu erzeugen } } close(DATEI); # letzten Satz auch noch ausgeben... print_row(); # ...und die Tabelle "schliessen" print "</table>\n"; # feddich ;) exit 0; ==== Ich denke, fuer dieses kleine scripterl sind die globalen Variablen angebracht... -dnh -- When you say "I wrote a program that crashed Windows", people just stare at you blankly and say "Hey, I got those with the system, *for free*". -Linus Torvalds
Am Mon, 2003-06-23 um 03.00 schrieb David Haller:
Hello,
On Mon, 23 Jun 2003, Jan Trippler wrote:
# Datei lesen die "usage: $0 Dateiname\n" unless defined $ARGV[0]; open DATEI, "$ARGV[0]" or die "Fehler beim Oeffnen der Datei ($!)\n";
Die Datei sollte man IMO explizit "readonly" oeffnen...
my @zeilen = <DATEI>; close DATEI;
*AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA*
Das ist der gleiche Fehler wie von grepmail. Versuch das mal mit ner Datei von ein paar 100 MB!!! 100MB Dateien sind ein extremer Sonderfall.
Ja, bei derartigen Extremfällen scheitert Einlesen in eine einzelne Liste, aber ...
Stehen lassen kann man das "open".
# meine Variablen my %daten = (); # der Hash fuer die Werte und Keys eines Datensatzes my @spalten = ("Kdnr", "Name", "Firma", "Beschreibung", "Telefon", "Zusatz");
# Tabellenheader print "<table width='100%' border='1'>\n"; print "<tr>\n"; foreach (@spalten) { printf "<th>%s</th>\n", $_; } print "</tr>\n";
foreach (@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt
*ARGH* Hier wird's dann wirklich doof, wenn man sowieso zeilenweise liest, kann man gleich die Datei hernehmen.
... Jan's Lösung ist schon bei Dateien mit wenigen 100 Zeilen um mehrere 10-Potenzen schneller. D.h. je nach Anwendungsgebiet ist mal die eine oder die andere Lösung sinnvoller, schneller oder "besser". Ralf
Hello, On Mon, 23 Jun 2003, Ralf Corsepius wrote:
Am Mon, 2003-06-23 um 03.00 schrieb David Haller: [..]
Das ist der gleiche Fehler wie von grepmail. Versuch das mal mit ner Datei von ein paar 100 MB!!! 100MB Dateien sind ein extremer Sonderfall.
Nicht bei grepmail... Das Teil frisst (oder frass zumindest) Speicher wie bekloppt. Je nach Hauptspeicher geht's halt ab einer gewissen Dateigroesse nicht mehr...
Ja, bei derartigen Extremfällen scheitert Einlesen in eine einzelne Liste, aber ... [..]
foreach (@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt
*ARGH* Hier wird's dann wirklich doof, wenn man sowieso zeilenweise liest, kann man gleich die Datei hernehmen.
... Jan's Lösung ist schon bei Dateien mit wenigen 100 Zeilen um mehrere 10-Potenzen schneller.
*huch* ;) Aehm, nunja, siehe unten.
D.h. je nach Anwendungsgebiet ist mal die eine oder die andere Lösung sinnvoller, schneller oder "besser".
Ack. Es wurde halt nix zur Dateigroesse gesagt, und bevor z.B. ein script wg. Speichermangel gar nicht laeuft, soll's ruhig etwas laenger laufen... So, nun interessiert mich das jetzt aber mal... ;) Ich hab mir mal ein paar Testdaten angelegt (script s.u.)... dh@slarty[3]: ~/src/perlbenches (0)$ ls -lh total 120M -rwxr--r-- 1 dh dh 2.0k Jun 24 00:05 dat2html_dh.pl -rwxr--r-- 1 dh dh 2.0k Jun 24 00:05 dat2html_dh_foreach.pl -rwxr--r-- 1 dh dh 2.0k Jun 24 00:05 dat2html_dh_noprint.pl -rwxr--r-- 1 dh dh 1.8k Jun 24 00:04 dat2html_jan.pl -rwxr--r-- 1 dh dh 704 Jun 23 23:36 gendata.pl -rw-r--r-- 1 dh dh 1.1k Jun 23 23:36 set1.dat -rw-r--r-- 1 dh dh 9.1k Jun 23 23:36 set2.dat -rw-r--r-- 1 dh dh 93k Jun 23 23:36 set3.dat -rw-r--r-- 1 dh dh 990k Jun 23 23:36 set4.dat -rw-r--r-- 1 dh dh 10M Jun 23 23:36 set5.dat -rw-r--r-- 1 dh dh 108M Jun 23 23:36 set6.dat dh@slarty[3]: ~/src/perlbenches (0)$ tail -2 dat2html_* ==> dat2html_dh.pl <== print STDERR `cat /proc/$$/status`; exit 0; ==> dat2html_dh_foreach.pl <== print STDERR `cat /proc/$$/status`; exit 0; ==> dat2html_dh_noprint.pl <== print STDERR `cat /proc/$$/status`; exit 0; ==> dat2html_jan.pl <== print STDERR `cat /proc/$$/status`; exit 0; dh@slarty[3]: ~/src/perlbenches (1)$ for s in dat2html_*; \ do \ echo "==== $s ====" >&2; \ for i in `seq 1 5`; \ do \ echo "set$i: " >&2; \ time perl $s "set${i}.dat" >/dev/null; \ done; \ done 2>&1 \ | awk '/^=/{print;}/^set/{t=$0;}/^VmSize/{t=t $0;}/real/{print t," ",$0}' ==== dat2html_dh.pl ==== set1: VmSize: 2800 kB real 0m0.095s set2: VmSize: 2808 kB real 0m0.152s set3: VmSize: 2808 kB real 0m0.606s set4: VmSize: 2812 kB real 0m5.527s set5: VmSize: 2812 kB real 0m51.129s ==== dat2html_dh_foreach.pl ==== set1: VmSize: 2800 kB real 0m0.064s set2: VmSize: 2856 kB real 0m0.134s set3: VmSize: 3428 kB real 0m0.602s set4: VmSize: 8960 kB real 0m5.517s set5: VmSize: 72648 kB real 0m54.077s ==== dat2html_dh_noprint.pl ==== set1: VmSize: 2800 kB real 0m0.188s set2: VmSize: 2808 kB real 0m0.099s set3: VmSize: 2808 kB real 0m0.493s set4: VmSize: 2812 kB real 0m4.259s set5: VmSize: 2808 kB real 0m41.551s ==== dat2html_jan.pl ==== set1: VmSize: 2800 kB real 0m0.063s set2: VmSize: 2856 kB real 0m0.128s set3: VmSize: 3424 kB real 0m0.559s set4: VmSize: 8952 kB real 0m4.777s set5: VmSize: 72636 kB real 0m47.534s Ei, gugge mol do... Nein, ich bin nicht ueberrascht ;) Ich glaube dir ja in der Regel, aber dass die 'while(<DATEI>)' Variante soo viel laenger brauchen sollte haette mich doch sehr gewundert... Also: ja, die "foreach" Variante ist marginal schneller, deine "mehere 10-Potenzen"[1] sind aber definitiv nicht nachvollziehbar. Und wenn man dann noch den Speicherverbrauch einbezieht, ist meine Meinung "*AAAAA*" nachvollziehbar gerechtfertigt. Der Speicherverbrauch bei "while(<DATEI>)" ist quasi konstant, im Gegenteil zu "@array=<DATEI>; foreach(@array);". Und ja, "set5" ist tatsaechlich nur mit der 10M Datei; auch noch set6 zu testen hat mir zu lange gedauert. Man achte insbesondere auf den Unterschied zwischen _dh.pl und _dh_foreach.pl, da der Unterschied (s.u.) der beiden scripte wirklich nur aus der Art besteht, wie die Datei eingelesen wird. Interessanterweise ist die foreach-Variante sogar langsamer, sobald die zu verarbeitende Datei groesser wird! -dnh PS: perl 5.8.0, selbst kompiliert PPS: bei Bedarf kann ich auch ein tar der Scripte mailen. [1] es ist ja nur eine ca. 7% laengere Laufzeit. Das ist nicht immer ein relevanter Unterschied, v.a. wenn man sich den Speicherverbrauch anschaut. ==== gendata.pl [quick & dirty, Performance egal] ==== #! /usr/bin/perl -w my @testcases = [ q[ Kdnr: 1211 Name: Schmitz, Peter Firma: Schmitz GmbH Beschreibung: Projekt XY, Netzwerkverkabelung Telefon: 0123 45678 Zusatz: Kunde will Angebot für VPN ], q[ Kdnr: 1219 Name: Müller, Franz Firma: Müller & Söhne GbR Beschreibung: Projekt AB, Datensicherung Beschreibung: Datensicherung Windows NT-Server Telefon: 0123 45678 ] ]; my ($i, $dat); for my $i ( 1 .. 6 ) { open(DAT, ">set$i.dat") or die $!; foreach(@testcases) { print DAT @{$_}; for( 1 .. (10 ** $i) ) { print DAT qq[ Kdnr: $_ Name: Name$_, $_ Firma: firma$_ Beschreibung: Beschreibung$_ Telefon: telefon$_ ]; } } close(DAT); } ==== ==== diffs fuer die Varianten ==== dh@slarty[3]: ~/src/perlbenches (1)$ diff -U1 dat2html_dh.pl dat2html_dh_noprint.pl --- dat2html_dh.pl Tue Jun 24 00:05:12 2003 +++ dat2html_dh_noprint.pl Tue Jun 24 00:05:03 2003 @@ -43,3 +43,3 @@ # ausgeben... - print_row(); + # print_row(); # ... und den hash reinitialisieren @@ -67,3 +67,3 @@ # letzten Satz auch noch ausgeben... -print_row(); +# print_row(); # ...und die Tabelle "schliessen" dh@slarty[3]: ~/src/perlbenches (1)$ diff -U1 dat2html_dh.pl dat2html_dh_foreach.pl --- dat2html_dh.pl Tue Jun 24 00:05:12 2003 +++ dat2html_dh_foreach.pl Tue Jun 24 00:05:08 2003 @@ -27,2 +27,4 @@ open(DATEI, "<$ARGV[0]") or die "Fehler beim Oeffnen der Datei: $!"; +my @zeilen = <DATEI>; +close(DATEI); @@ -36,3 +38,3 @@ -while(<DATEI>) { # Zeilen abklappern, Zeile wird in $_ abgelegt +foreach(@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt next if /^\s*$/; # leere Zeilen wegschmeissen @@ -64,3 +66,2 @@ } -close(DATEI); ==== Und wie gesagt, ich hab in allen 4 scripten noch das print STDERR `cat /proc/$$/status`; eingefuegt, ansonsten entsprechen die scripte den gemailten Versionen. -- Das Problem ist vermutlich auf schlechte Erdung zurueckzufuehren. Schlagt einfach zwei Stahlnaegel in die Turnschuhe eures MCSEs. So koennen die Ueberspannungen aus dem Kopf abfliessen, und Euer Mann achtet auch mehr auf seine Sicherheit in der Naehe von Computern. -- M. Liss in dasr
Am Die, 2003-06-24 um 00.50 schrieb David Haller:
Hello,
On Mon, 23 Jun 2003, Ralf Corsepius wrote:
Am Mon, 2003-06-23 um 03.00 schrieb David Haller: [..]
Das ist der gleiche Fehler wie von grepmail. Versuch das mal mit ner Datei von ein paar 100 MB!!! 100MB Dateien sind ein extremer Sonderfall.
Nicht bei grepmail... Das Teil frisst (oder frass zumindest) Speicher wie bekloppt. Je nach Hauptspeicher geht's halt ab einer gewissen Dateigroesse nicht mehr...
.. eben, 100MB im Speicher sind heutzutage (auf Home-Desktops noch) nicht normal.
Ja, bei derartigen Extremfällen scheitert Einlesen in eine einzelne Liste, aber ... [..]
foreach (@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt
*ARGH* Hier wird's dann wirklich doof, wenn man sowieso zeilenweise liest, kann man gleich die Datei hernehmen.
... Jan's Lösung ist schon bei Dateien mit wenigen 100 Zeilen um mehrere 10-Potenzen schneller.
*huch* ;) Aehm, nunja, siehe unten.
In einer vergleichbaren Anwendung habe ich schon Faktor ca. 20-50 beobachtet (mit perl < 0.5.6)
D.h. je nach Anwendungsgebiet ist mal die eine oder die andere Lösung sinnvoller, schneller oder "besser".
Ack. Es wurde halt nix zur Dateigroesse gesagt, und bevor z.B. ein script wg. Speichermangel gar nicht laeuft, soll's ruhig etwas laenger laufen... Im einem Fall war es ein Code-Generator, der ca. 100 Mal pro "make" Lauf aufgerufen wird. < 0.5 sec statt > 10 sec wirken sich dabei deutlich aus.
So, nun interessiert mich das jetzt aber mal... ;)
Die Rechnung ist im Prinzip einfach: 1 x File-I/O + n x Mem-Zugriff gegen n x ( File-I/O + Mem-Zugriff ) [Leg die Dateien auf ein nfs-gemountetes File-System und/oder ein mit I/O belastes System.] Mag sein, dass neuere Perl/glibc/Linux-Implementierungen ein günstigers Caching verwenden als ältere Versionen oder sich neuere HW derart auswirkt, dass die Performanceunterschiede nicht mehr so gravierend auswirken. Ralf
Hallo, On Tue, 24 Jun 2003, Ralf Corsepius wrote:
Am Die, 2003-06-24 um 00.50 schrieb David Haller:
On Mon, 23 Jun 2003, Ralf Corsepius wrote:
In einer vergleichbaren Anwendung habe ich schon Faktor ca. 20-50 beobachtet (mit perl < 0.5.6)
Hm. Hab's mal mit 5.005 getestet, s.u., ist das alt genug?
D.h. je nach Anwendungsgebiet ist mal die eine oder die andere Lösung sinnvoller, schneller oder "besser".
Ack. Es wurde halt nix zur Dateigroesse gesagt, und bevor z.B. ein script wg. Speichermangel gar nicht laeuft, soll's ruhig etwas laenger laufen... Im einem Fall war es ein Code-Generator, der ca. 100 Mal pro "make" Lauf aufgerufen wird. < 0.5 sec statt > 10 sec wirken sich dabei deutlich aus.
Jup. Da ist aber perl sowieso eher weniger geeignet.
So, nun interessiert mich das jetzt aber mal... ;)
Die Rechnung ist im Prinzip einfach:
1 x File-I/O + n x Mem-Zugriff gegen n x ( File-I/O + Mem-Zugriff )
[Leg die Dateien auf ein nfs-gemountetes File-System und/oder ein mit I/O belastes System.]
Mag sein, dass neuere Perl/glibc/Linux-Implementierungen ein günstigers Caching verwenden als ältere Versionen oder sich neuere HW derart auswirkt, dass die Performanceunterschiede nicht mehr so gravierend auswirken.
Hab ich mal getestet, parallel zu einem 'dd if=./set5.dat of=/dev/null' in einer Endlosschleife... dh@slarty[3]: ~/src/perlbenches (130)$ for s in dat2html_*; do echo \ "==== $s ==">&2; for i in 5; do echo "set$i: ">&2; time \ /usr/bin/perl5.00503 $s "set${i}.dat" >/dev/null; done; done 2>&1 \ | awk '/^=/{print;}/^set/{t=$0;}/^VmSize/{t=t $0;}/real/{print t," ",$0}' ==== dat2html_dh.pl ==== set5: VmSize: 2528 kB real 1m6.266s ==== dat2html_dh_foreach.pl ==== set5: VmSize: 56072 kB real 1m16.403s ==== dat2html_dh_noprint.pl ==== set5: VmSize: 2528 kB real 0m50.156s ==== dat2html_jan.pl ==== set5: VmSize: 56072 kB real 1m7.710s dh@slarty[3]: ~/src/perlbenches (0)$ for s in dat2html_*; do echo \ "==== $s ====">&2; for i in 5; do echo "set$i: ">&2; time \ /usr/local/bin/perl5.8.0 $s "set${i}.dat" >/dev/null; done; done 2>&1 \ | awk '/^=/{print;}/^set/{t=$0;}/^VmSize/{t=t $0;}/real/{print t," ",$0}' ==== dat2html_dh.pl ==== set5: VmSize: 2668 kB real 1m41.323s ==== dat2html_dh_foreach.pl ==== set5: VmSize: 72416 kB real 1m45.644s ==== dat2html_dh_noprint.pl ==== set5: VmSize: 2664 kB real 1m22.107s ==== dat2html_jan.pl ==== set5: VmSize: 72416 kB real 1m34.497s Man achte wiederrum auf den Speicherverbrauch... -dnh -- 132: Plug and Play Kondome. (Rolf Siebrecht)
On Mon, 23 Jun 2003 at 03:00 (+0200), David Haller wrote:
On Mon, 23 Jun 2003, Jan Trippler wrote:
# Datei lesen die "usage: $0 Dateiname\n" unless defined $ARGV[0]; open DATEI, "$ARGV[0]" or die "Fehler beim Oeffnen der Datei ($!)\n";
Die Datei sollte man IMO explizit "readonly" oeffnen...
my @zeilen = <DATEI>; close DATEI;
*AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA*
Das ist der gleiche Fehler wie von grepmail. Versuch das mal mit ner Datei von ein paar 100 MB!!! Stehen lassen kann man das "open".
Ich habe hier einfach die Vorlage übernommen - ich benutze dieses Konstrukt auch oft, wenn ich weiss, dass die Dateien überschaubar sind. Der Vorteil: Du hast das Array immer bei der Hand, wenn Du es nochmal brauchst, ohne den Dateipointer zurücksetzen zu müssen oder die Datei neu einlesen zu müssen. Ist einfach bequem und ich werde es (mit der o. g. Einschränkung) auch weiterhin gern nutzen ;-) Für mehrere 100 MB fehlte mir die Geduld, aber ich habe mal eine Datei mit 150.000 Datensätzen generiert (meine 3 Testsätze einfach 50.000 mal aneinandergehängt, ergab ca. 19 MB): Die Testsätze: <schnipp> jan@k500:~/tmp> cat kunden Kdnr: 1211 Name: Schmitz, Peter Firma: Schmitz GmbH Beschreibung: Projekt XY, Netzwerkverkabelung Telefon: 0123 45678 Zusatz: Kunde will Angebot für VPN Kdnr: 1219 Name: Müller, Franz Firma: Müller & Söhne GbR Beschreibung: Projekt AB, Datensicherung Beschreibung: Datensicherung Windows NT-Server Telefon: 0123 45678 Kdnr: 1239 Name: Miller, Granz Firma: Miller & Söhne GbR Telefon: 0123 45678 <schnapp> Meine Variante: jan@k500:~/tmp> time ./out.pl >kunden.html real 7m32.256s user 5m45.190s sys 0m6.340s Deine Variante: jan@k500:~/tmp> time ./out.pl >kunden2.html real 7m25.972s user 5m54.390s sys 0m5.440s Hm, diese Differenz ist für mich vernachlässigbar.
# meine Variablen my %daten = (); # der Hash fuer die Werte und Keys eines Datensatzes my @spalten = ("Kdnr", "Name", "Firma", "Beschreibung", "Telefon", "Zusatz");
# Tabellenheader print "<table width='100%' border='1'>\n"; print "<tr>\n"; foreach (@spalten) { printf "<th>%s</th>\n", $_; } print "</tr>\n";
foreach (@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt
*ARGH* Hier wird's dann wirklich doof, wenn man sowieso zeilenweise liest, kann man gleich die Datei hernehmen.
while(<DATEI>) { # Zeilen abklappern, Zeile wird in $_ abgelegt
(ja, der Kommentar stimmt so!)
Es wird nur dann doof, wenn Du sie nicht in ein Array gelesen hast. Wenn Du unbedingt zeilenweise lesen willst, kannst Du natürlich nicht über ein Array iterieren.
chomp; # \n wegwerfen next if /^ *$/; # leere Zeilen wegschmeissen
Wuerde ich andersrum schreiben, bei leeren Zeilen faellt dann der ueberfluessige Aufruf von 'chomp' weg:
next if /^\s*$/; # leere Zeilen wegschmeissen chomp; # \n wegwerfen
Jau, spart einen Funktionsaufruf.
if (defined ($daten{'Kdnr'}) && /^Kdnr/) { # $_ faengt mit KdNr an print "<tr>\n"; # Tabellenzeile foreach my $out (@spalten) { # Spalten abklappern if (defined $daten{$out}) { # Key vorhanden? printf "<td>%s</td>\n", $daten{$out}; # Ja: Wert schreiben undef ($daten{$out}); # Hash-Key wegschmeissen
Ich wuerde eher jew. beim Auftauchen von 'Kdnr' das gesamte hash reinitialisieren:
if (defined ($daten{'Kdnr'}) && /^Kdnr/) { # $_ faengt mit KdNr an print "<tr>\n"; # Tabellenzeile foreach my $out (@spalten) { # Spalten abklappern if (defined $daten{$out}) { # Key vorhanden? printf "<td>%s</td>\n", $daten{$out}; # Ja: Wert schreiben } else { print "<td> </td>\n"; # Nein: Leerzeichen } } print "</tr>\n"; # Ende Tabellenzeile %daten = (); # hash reinitialisieren }
## in $_ steht immer noch das neue Kdnr: ...
Was ist der Unterschied? Ich initialisiere zwar nicht das ganze Array, weil ich nur alle (in der Tabelle benutzten) Keys plattmache. Der Effekt ist aber der gleiche. Ich weiss nicht, wie Perl das intern handhabt und was performanter ist. Nachtrag: Die oberen beiden Tests liefen mit Deiner Variante der Initialisierung. Aus Neugier habe ich mal meine ursprüngliche Version laufen lassen (undef der einzelnen Keys): jan@k500:~/tmp> time ./out.pl >kunden3.html real 6m28.514s user 5m20.590s sys 0m5.220s Und der Vollständigkeit halber mit zeilenweisem Lesen: jan@k500:~/tmp> time ./out.pl >kunden4.html real 6m54.461s user 5m36.530s sys 0m5.420s Ich kann mir die einzelnen Abweichungen auch nicht 100% erklären (ich bin ja nicht die SPEC und habe die Dinger einfach nacheinander laufen lassen - also keine klinisch reine Testumgebung ;-), aber IMHO zeigt das, dass die Initialisierung einzelner Keys deutlich fixer ist, als die des gesamten Hash (immerhin ca. 15%).
my ($key, $value) = split /:/; # neue Zeile aufspalten
Die Deklaration wuerde ich aus der Schleife rausnehmen, das ist nicht noetig. Also das 'my ($key, $value)' vor das while und dann hier nur noch:
($key, $value) = split /:/; # neue Zeile aufspalten
Warum? Mit einer lokalen Deklaration bin ich sicher, dass die Variablen nirgends sonst irrtümlich benutzt werden, da weist mich perl schon drauf hin. Du führst unnötig global gültige Variablen ein, das ist IMHO ein Weg, der Fehler provoziert. Global definierte Variablen verführen immer dazu, sie einfach noch mal zu benutzen (oder aus Versehen noch mal zu benutzen - perl warnt ja dann nicht mehr), und dann wird es deutlich aufwändiger, Seiteneffekte zu vermeiden.
Ich denke, fuer dieses kleine scripterl sind die globalen Variablen angebracht...
s. o. Jan
Hello, On Tue, 24 Jun 2003, Jan Trippler wrote:
On Mon, 23 Jun 2003 at 03:00 (+0200), David Haller wrote:
On Mon, 23 Jun 2003, Jan Trippler wrote:
# Datei lesen die "usage: $0 Dateiname\n" unless defined $ARGV[0]; open DATEI, "$ARGV[0]" or die "Fehler beim Oeffnen der Datei ($!)\n";
Die Datei sollte man IMO explizit "readonly" oeffnen...
my @zeilen = <DATEI>; close DATEI;
*AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA*
Das ist der gleiche Fehler wie von grepmail. Versuch das mal mit ner Datei von ein paar 100 MB!!! Stehen lassen kann man das "open".
Ich habe hier einfach die Vorlage übernommen - ich benutze dieses Konstrukt auch oft, wenn ich weiss, dass die Dateien überschaubar sind.
Ja. [..]
jan@k500:~/tmp> time ./out.pl >kunden.html real 7m32.256s Deine Variante: jan@k500:~/tmp> time ./out.pl >kunden2.html real 7m25.972s
Hm, diese Differenz ist für mich vernachlässigbar.
Hast du auch mal den Speicherverbrauch dabei angeschaut? Siehe dazu meine tests nebenan ;)
foreach (@zeilen) { # Zeilen abklappern, Zeile wird in $_ abgelegt
*ARGH* Hier wird's dann wirklich doof, wenn man sowieso zeilenweise liest, kann man gleich die Datei hernehmen.
while(<DATEI>) { # Zeilen abklappern, Zeile wird in $_ abgelegt
(ja, der Kommentar stimmt so!)
Es wird nur dann doof, wenn Du sie nicht in ein Array gelesen hast. Wenn Du unbedingt zeilenweise lesen willst, kannst Du natürlich nicht über ein Array iterieren.
Klar, ich haette da vielleicht '...' verwenden sollen. Das bezog sich auch noch darauf, dass ueberhaupt in ein Array gelesen wird. Liest man in ein Array, dann ist das foreach natuerlich richtig ;)
chomp; # \n wegwerfen next if /^ *$/; # leere Zeilen wegschmeissen
Wuerde ich andersrum schreiben, bei leeren Zeilen faellt dann der ueberfluessige Aufruf von 'chomp' weg:
next if /^\s*$/; # leere Zeilen wegschmeissen chomp; # \n wegwerfen
Jau, spart einen Funktionsaufruf.
Ich versuch immer so zu programmieren...
undef ($daten{$out}); # Hash-Key wegschmeissen
Ich wuerde eher jew. beim Auftauchen von 'Kdnr' das gesamte hash reinitialisieren: [..] print "</tr>\n"; # Ende Tabellenzeile %daten = (); # hash reinitialisieren }
## in $_ steht immer noch das neue Kdnr: ...
Was ist der Unterschied? Ich initialisiere zwar nicht das ganze Array, weil ich nur alle (in der Tabelle benutzten) Keys plattmache. Der Effekt ist aber der gleiche.
Jup.
Ich weiss nicht, wie Perl das intern handhabt und was performanter ist.
Nachtrag: Die oberen beiden Tests liefen mit Deiner Variante der Initialisierung. [..] IMHO zeigt das, dass die Initialisierung einzelner Keys deutlich fixer ist, als die des gesamten Hash (immerhin ca. 15%).
Jo, scheint so. $ time perl -e 'for ( 0 .. 500000 ) { $foo{$_} = $_; } undef %foo;' real 0m6.133s $ time perl -e 'for ( 0 .. 500000 ) { $foo{$_} = $_; } %foo = ();' real 0m6.080s $ time perl -e 'for ( 0 .. 500000 ) { $foo{$_} = $_; undef($foo{$_}); }' real 0m5.487s Die 'sys' Werte sind jew. irrelevant aehnlich. Hm. Die ltrace (-S) Ausgaben sehen in beiden Varianten aehnlich aus... Ich dachte grad, dass perl bei der letzteren Variante speicher recylced, aber das scheint auch sonst der Fall zu sein: $ ltrace -S perl -e 'for ( 0 .. 50 ) { $foo{$_} = $_; undef($foo{$_}); }' 2>&1 | grep 'SYS_brk' | wc -l 23 $ ltrace -S perl -e 'for ( 0 .. 50 ) { $foo{$_} = $_; } undef(%foo);' 2>&1 | grep 'SYS_brk' | wc -l 23 'Alloc' taucht jew. nur einmal als perl_alloc auf... Also leider nichts erhellendes, warum das eine oder andere schneller ist... Da muesste man wohl mal in die perl-Sourcen schauen... Ich habe eben vermutet, dass die "vielen einzelnen" undefs langsamer waeren als ein einzelnes "wegwerfen"/reinitialisieren des hashes...
my ($key, $value) = split /:/; # neue Zeile aufspalten
Die Deklaration wuerde ich aus der Schleife rausnehmen, das ist nicht noetig. Also das 'my ($key, $value)' vor das while und dann hier nur noch:
($key, $value) = split /:/; # neue Zeile aufspalten
Warum?
Bin wieder in die Falle getappt... $ time perl -e 'for ( 0 .. 500000 ) { my %foo; $foo{$_} = $_; undef($foo{$_}); }' real 0m4.678s $ time perl -e 'my %foo; for ( 0 .. 500000 ) { $foo{$_} = $_; undef($foo{$_}); }' real 0m6.323s Das soll mir mal einer erklaeren ;) Ich glaub, ich sollte echt mal ein wenig im perl-quellcode kruschteln ;)
Mit einer lokalen Deklaration bin ich sicher, dass die Variablen nirgends sonst irrtümlich benutzt werden, da weist mich perl schon drauf hin. Du führst unnötig global gültige Variablen ein, das ist IMHO ein Weg, der Fehler provoziert.
Ack. Sowas wuerde ich sonst in einem sub haben...
Global definierte Variablen verführen immer dazu, sie einfach noch mal zu benutzen (oder aus Versehen noch mal zu benutzen - perl warnt ja dann nicht mehr), und dann wird es deutlich aufwändiger, Seiteneffekte zu vermeiden.
ACK. -dnh --
Rai"Ohje Du fröhliche"mund "...gnadenlose Weihnachtszeit. -- R. Huemmer und M. Herrmann in dasr
On Mit, 25 Jun 2003 at 01:58 (+0200), David Haller wrote:
On Tue, 24 Jun 2003, Jan Trippler wrote: [..]
jan@k500:~/tmp> time ./out.pl >kunden.html real 7m32.256s Deine Variante: jan@k500:~/tmp> time ./out.pl >kunden2.html real 7m25.972s
Hm, diese Differenz ist für mich vernachlässigbar.
Hast du auch mal den Speicherverbrauch dabei angeschaut? Siehe dazu meine tests nebenan ;)
Och, da brauche ich keine Tests ;-) Es ist ja logisch, dass der Speicherverbrauch zumindest um die Größe der Datei anwächst, wenn ich sie in ein Array lese. Darum auch meine früher erwähnte Einschränkung in Bezug auf die Überschaubarkeit der zu lesenden Dateien. Es hängt immer vom konkreten Anwendungsfall ab, was man macht. Spätestens wenn man den Dateiinhalt an mehreren Stellen braucht, gehts IMHO deutlich schneller, in einem Array zu manövrieren, als den Dateipointer hin- und herzuschieben. Jan
Hallo zusammen, hallo David und Jan! Erstmal vielen Dank für die zahlreichen Zuschriften, ich komme der Lösung langsam näher. Leider ist die von David vorgestellte Lösung noch nicht ganz das, was ich brauche. Ich habe mich in meinem Posting wahrscheinlich schlecht ausgedrückt. Die Liste sieht ja wie folgt aus (mit all ihren Problemen und Unvollständigkeiten etc): Kdnr: 1211 Name: Schmitz, Peter Firma: Schmitz GmbH Beschreibung: Projekt XY, Netzwerkverkabelung Telefon: 0123 45678 Zusatz: Kunde will Angebot für VPN So David's Lösung schreibt alle Werte für "Kdnr", "Name", "Firma" etc. in eine Spalte und liefert deshalb insgesamt nur einen Datensatz zurück. Ich möchte aber gerne für jeden einzelnen Kunden eine einzelne Zeile, also etwa so (senkrechte Striche symbolisieren die HTML-Tabelle bzw. jeweils eine SPALTE davon): 1211 | Schmitz, Peter | Schmitz GmbH | Projekt XY, Netzwerkverkabelung | 0123 45678 | Kunde will Angebot für VPN Vielleicht habe ich mich da etwas schlecht ausgedrückt. Wenn ich also in einer Kundendatenbank beispielsweise 50 verschiedenen Kunden hätte, müsste das Skript eine HTML-Tabelle mit 50 Zeilen und den paar Spalten ausspucken...Wie müsste dafür die Lösung ausschauen? Vielen Dank für die Hilfe, ihr seid die Besten :-) Viele Grüße, Werner.
Hi
So David's Lösung schreibt alle Werte für "Kdnr", "Name", "Firma" etc. in eine Spalte und liefert deshalb insgesamt nur einen Datensatz zurück. Ich möchte aber gerne für jeden einzelnen Kunden eine einzelne Zeile, also etwa so (senkrechte Striche symbolisieren die HTML-Tabelle bzw. jeweils eine SPALTE davon):
1211 | Schmitz, Peter | Schmitz GmbH | Projekt XY, Netzwerkverkabelung | 0123 45678 | Kunde will Angebot für VPN
Vielleicht habe ich mich da etwas schlecht ausgedrückt. Wenn ich also in einer Kundendatenbank beispielsweise 50 verschiedenen Kunden hätte, müsste das Skript eine HTML-Tabelle mit 50 Zeilen und den paar Spalten ausspucken...Wie müsste dafür die Lösung ausschauen?
Du hast doch eine Loesung bekommen, wie Du die Daten Datensatzweise einlesen kannst. Wenn Du daraus keine Zeile einer HTML-Tabelle formulieren kannst, dann solltest Du noch mal zu den Grundlagen zurückkehren und Dich etwas einlesen. Und dann ist es vielleicht auch noch nicht zu spaet von Perl auf PHP amzusteigen. Bye -- 1 Bodo Kaelberer 123 http://www.webkind.de/ 3 4 "A button I have made must be pushed." (ip)
On Die, 24 Jun 2003 at 10:12 (+0200), Werner Schalk wrote: [...]
So David's Lösung schreibt alle Werte für "Kdnr", "Name", "Firma" etc. in eine Spalte und liefert deshalb insgesamt nur einen Datensatz zurück. Ich möchte aber gerne für jeden einzelnen Kunden eine einzelne Zeile, also etwa so (senkrechte Striche symbolisieren die HTML-Tabelle bzw. jeweils eine SPALTE davon):
1211 | Schmitz, Peter | Schmitz GmbH | Projekt XY, Netzwerkverkabelung | 0123 45678 | Kunde will Angebot für VPN
Vielleicht habe ich mich da etwas schlecht ausgedrückt. Wenn ich also in einer Kundendatenbank beispielsweise 50 verschiedenen Kunden hätte, müsste das Skript eine HTML-Tabelle mit 50 Zeilen und den paar Spalten ausspucken...Wie müsste dafür die Lösung ausschauen?
Warum hast Du Dir meine Lösung nicht angeschaut? Die (und IIRC auch die von David) liefert _exakt_ die von Dir gewünschte HTML-Tabelle (inklusive Header). Das jedes <td>-Element in einer Zeile steht, ist für die HTML-Darstellung völlig irrelevant - und wenn Dir die Formatierung nicht gefällt, dann ändere sie doch! Manchmal frage ich mich, warum ich Dösbaddel mich hinsetze und das Ganze extra noch teste, wenn sich die Fragenden nicht mal die Antworten genau angucken >:-< Jan
Hallo, ich bedanke mich wirklich sehr herzliche für eure Hilfe und ich habe mir diese genaustens angesehen, aber der Output ist EINE Zeile mit allen Ergebnissen, ich möchte aber eine Zeile JE Kundendatensatz. Daher ist dieser Output nicht wie gewünscht (sowohl von Jans, als auch von Davids Programm): <table width='100%' border='1'> <tr> <th>Kdnr</th> <th>Name</th> <th>Firma</th> <th>Beschreibung</th> <th>Telefon</th> <th>Zusatz</th> </tr> <tr> <td>4711, 1382, 1442, 999</td> <td>Meier, Schmitz, Müller, Peters</td> <td>Meier GmbH, Schmitz und Söhne GbR, Peters and friends GmbH</td> <td>[...]</td> </tr> </table> Da ich den Perlcode nicht vollkommen verstehe, wollte ich wissen, wie dieser modifiziert werden muss, damit der Output etwa so ausschaut: <table width='100%' border='1'> <tr> <th>Kdnr</th> <th>Name</th> <th>Firma</th> <th>Beschreibung</th> <th>Telefon</th> <th>Zusatz</th> </tr> <tr> <td>4711</td> <td>Meier</td> <td>Meier GmbH</td> <td>[...]</td> </tr> <tr> <td>1382</td> <td>Schmitz</td> <td>Schmitz und Söhne GbR</td> <td>[...]</td> </tr> </table> Ich möchte mich für die Mißverständnisse entschuldigen und bedanke mich nochmals für euren Einsatz und eure Hilfe. Ein kleiner Textanstoß wäre schon toll... Vielen Dank und schöne Grüße, Werner.
Ich möchte mich für die Mißverständnisse entschuldigen und bedanke mich nochmals für euren Einsatz und eure Hilfe. Ein kleiner Textanstoß wäre schon toll...
Wenn Du den Code nicht verstehst, dann moechte ich mal wissen, woher Du Deinen eigenen hattest. Dir ist auch laengerfristig nicht damit geholfe, dass andere die simpelsten Aufgaben fuer die durchkauen. Also schau Dir die Sprache Deiner Wahl (manche machen es sich ja gerne schwer) noch mal fuer ein paar Tage an statt hier tagelang darauf zu warten, dass andere Deine Probleme loesen. -- 1 Bodo Kaelberer 123 http://www.webkind.de/ 3 4 "A button I have made must be pushed." (ip)
On Die, 24 Jun 2003 at 23:18 (+0200), Bodo Kaelberer wrote: [...] - Ich lese die Liste mit und brauche keine Kopie! - Warum motzt Du hier rum? Wenn es David/mir/anderen zu viel wird, dann schreiben wir das schon, keine Bange. - Wenn Du nichts zur Lösung beitragen willst, lösche den Thread doch einfach. Dass Werner unseren Code nicht auf Anhieb rafft, ist doch kein Verbrechen! Missverständnisse kommen nun mal vor und können hier ohne großes Trallala sachlich geklärt werden. Jan
On Die, 24 Jun 2003 at 22:24 (+0200), Werner Schalk wrote: Zuerst eine Bitte: Schicke Antworten bitte nur an die Liste, ich lese mit und brauche keine private Kopie.
ich bedanke mich wirklich sehr herzliche für eure Hilfe und ich habe mir diese genaustens angesehen, aber der Output ist EINE Zeile mit allen Ergebnissen, ich möchte aber eine Zeile JE Kundendatensatz. Daher ist dieser Output nicht wie gewünscht (sowohl von Jans, als auch von Davids Programm):
<table width='100%' border='1'> <tr> <th>Kdnr</th> <th>Name</th> <th>Firma</th> <th>Beschreibung</th> <th>Telefon</th> <th>Zusatz</th> </tr> <tr> <td>4711, 1382, 1442, 999</td> <td>Meier, Schmitz, Müller, Peters</td> <td>Meier GmbH, Schmitz und Söhne GbR, Peters and friends GmbH</td> <td>[...]</td> </tr> </table>
Da ich den Perlcode nicht vollkommen verstehe, wollte ich wissen, wie dieser modifiziert werden muss, damit der Output etwa so ausschaut:
<table width='100%' border='1'> <tr> <th>Kdnr</th> <th>Name</th> <th>Firma</th> <th>Beschreibung</th> <th>Telefon</th> <th>Zusatz</th> </tr> <tr> <td>4711</td> <td>Meier</td> <td>Meier GmbH</td> <td>[...]</td> </tr> <tr> <td>1382</td> <td>Schmitz</td> <td>Schmitz und Söhne GbR</td> <td>[...]</td> </tr> </table>
Ich weiss nicht, welches Programm Du da laufen lässt, ich habe eben noch mal mein Script gestartet und es produziert genau den Output, den Du haben willst. Ich schicke Dir das Script vorsichtshalber noch mal per PM (inkl. meiner Quelldatei und der erzeugten HTML-Datei), das muss nicht nochmal über die Liste laufen. Jan
participants (5)
-
Bodo Kaelberer
-
David Haller
-
Jan.Trippler@t-online.de
-
Ralf Corsepius
-
Werner Schalk