Text::ParseWords - chomp
am 12.05.2007 16:06:25 von t_pot
Tach!
Ich beackere seit geraumer Zeit eine Datenbank (temporär CSV), in der das
letzte Feld nur sporadisch mit einem Wert belegt ist. Erst jetzt ist mir
aufgefallen, daß bei Verwendung des o.g. Moduls folgendes Phänomen
auftritt: Ich bekomme /warnings/ für alle Datensätze, in denen das
letzte Feld leer ist und das somit mit einem /;/ endet: "Use of
uninitialized value at ..."
Hier mal ein Beispielschnipsel:
#! /usr/bin/perl -w
#
use strict;
use Text::ParseWords;
#
my $TheLine = "";
my @array = ();
#
while () {
$TheLine = $_;
chomp ($TheLine);
#
@array = "ewords(";", 1, $TheLine);
$TheLine = join (";", @array);
print STDOUT "$TheLine\n";
}
__DATA__
"ene";"mene";"miste";
"es";"rappelt";"in";"der"
"kiste";"jawoll";"ja";
Bislang war ich der Auffassung, daß /chomp/ im Hinblick auf die
Zeilenende-Konventionen system-übergreifend funktioniert.
Zitat aus Ulrich Cuber: Linux Scripting, S. 331 (Perl-Programmierung):
"Die Funktion chomp () stellt eine brauchbare Variante von chop () dar.
Sie ist auf Zeilenenden spezialisiert. Und dies unter Berücksichtigung
der verschiedenen Konventionen der Betriebs-Systeme."
Ist aber offensichtlich nicht der Fall. Die CSV-Dateien kommen von der
Windows-Plattform, und ich habe mir zunächst einen Wolf gesucht, warum
ein Muster wie /^".+;"ja";$/ nicht matcht. Das /CR/ bleibt nämlich hängen,
und erst, wenn man die Dateien durch /recode/ nudelt, hat man wirklich
_saubere_ Zeilenenden. Dann allerdings kommen die o.g. /warnings/.
Die wiederum lassen sich vermeiden, wenn /chomp/ direkt /$_/ anfasst;
allerdings habe ich dann zwischen den Datensätzen Leerzeilen.
Was läuft da flasch? Das Skript tut ansonsten, was es soll, aber ich
würde schon gern wissen, warum /chomp (TheLine)/ die /warnings/
bei /join ()/ produziert und /chomp $_/ die Leerzeilen.
Vielleicht weiss ja jemand eine grundsätzliche Erklärung, ohne das o.g.
Modul im Detail zu kennen...
Aso: Perl 5.005-3 auf Debian Potato und 5.6.1 auf Debian Woody. (Schon
etwas angestaubt, ich weiss ...).
TIA,
--
Thomas Pothmann
PGP-Key on demand
Re: Text::ParseWords - chomp
am 12.05.2007 18:56:49 von Hermann Martinelli
> Bislang war ich der Auffassung, daß /chomp/ im Hinblick auf die
> Zeilenende-Konventionen system-übergreifend funktioniert.
Ich glaube, der chomp ist nicht das Problem.
Sehr seltsam:
Habe den chomp mal umgangen und Data::Dumper benutzt.
Skript und Ausgabe siehe unter meiner Signatur.
Seltsam, dass sich Perl beschwert, dass man ein undefinierts
Element im join() verarbeitet. Laut Dumper ist das letzte
Element in den beiden "Problemzeilen" ja undefiniert (undef).
Wenn join() kein undef als Wert akzeptiert, dann müsste
das folgende ja auch einen Fehler ausgeben:
perl -e 'print join( " - ", ("a", "b", undef) );
Tut es aber nicht.
Hmmmm.
Grüße
HME
#! /usr/bin/perl -w
use strict;
use warnings;
use Text::ParseWords;
use Data::Dumper;
while () {
s/[\r\n]*$//;
my @elements = parse_line(';', 1, $_);
print Dumper(@elements);
my $listing = join " - ", @elements;
print "Elements: |$listing|\n";
}
__DATA__
"ene";"mene";"miste";
"es";"rappelt";"in";"der"
"kiste";"jawoll";"ja";
Ausgabe:
$VAR1 = '"ene"';
$VAR2 = '"mene"';
$VAR3 = '"miste"';
$VAR4 = undef;
Use of uninitialized value in join or string at C:\test\test.pl line 12,
lin
Elements: |"ene" - "mene" - "miste" - |
$VAR1 = '"es"';
$VAR2 = '"rappelt"';
$VAR3 = '"in"';
$VAR4 = '"der"';
Elements: |"es" - "rappelt" - "in" - "der"|
$VAR1 = '"kiste"';
$VAR2 = '"jawoll"';
$VAR3 = '"ja"';
$VAR4 = undef;
Use of uninitialized value in join or string at C:\test\test.pl line 12,
lin
Elements: |"kiste" - "jawoll" - "ja" - |
Re: Text::ParseWords - chomp
am 12.05.2007 20:23:53 von Christian Winter
Hermann Martinelli schrieb:
> Wenn join() kein undef als Wert akzeptiert, dann müsste
> das folgende ja auch einen Fehler ausgeben:
>
> perl -e 'print join( " - ", ("a", "b", undef) );
>
> Tut es aber nicht.
Versuch's mal mit "perl -we" oder "use warnings". Join mag
kein undef. Also am besten etwas wie
print join " - ", map { $_ || "" } @werte;
verwenden.
-Christian
Re: Text::ParseWords - chomp
am 12.05.2007 22:06:19 von Frank Seitz
Thomas Pothmann wrote:
> Bislang war ich der Auffassung, daß /chomp/ im Hinblick auf die
> Zeilenende-Konventionen system-übergreifend funktioniert.
Diese Annahme ist falsch. Chomp entfernt den Wert
von $/ am Zeilenende und sonst nichts. Siehe Doku.
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Text::ParseWords - chomp
am 12.05.2007 22:06:22 von Frank Seitz
Christian Winter wrote:
> Hermann Martinelli schrieb:
>>
>>Wenn join() kein undef als Wert akzeptiert, dann müsste
>>das folgende ja auch einen Fehler ausgeben:
>>
>>perl -e 'print join( " - ", ("a", "b", undef) );
>>
>>Tut es aber nicht.
>
> Versuch's mal mit "perl -we" oder "use warnings". Join mag
> kein undef. Also am besten etwas wie
> print join " - ", map { $_ || "" } @werte;
> verwenden.
Der Code ist nicht korrekt, denn er ersetzt 0 durch ''.
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Text::ParseWords - chomp
am 13.05.2007 19:33:18 von Christian Winter
Frank Seitz schrieb:
> Christian Winter wrote:
>> Hermann Martinelli schrieb:
>>> Wenn join() kein undef als Wert akzeptiert, dann müsste
>>> das folgende ja auch einen Fehler ausgeben:
>>>
>>> perl -e 'print join( " - ", ("a", "b", undef) );
>>>
>>> Tut es aber nicht.
>> Versuch's mal mit "perl -we" oder "use warnings". Join mag
>> kein undef. Also am besten etwas wie
>> print join " - ", map { $_ || "" } @werte;
>> verwenden.
>
> Der Code ist nicht korrekt, denn er ersetzt 0 durch ''.
Stimmt, dabei wär's noch gar nicht so spät am Abend gewesen.
print join " - ", map { defined($_) ? $_ : "" } @werte;
-Christian
Re: Text::ParseWords - chomp
am 14.05.2007 18:23:15 von t_pot
Christian Winter wrote:
>Frank Seitz schrieb:
>> Christian Winter wrote:
>>> Hermann Martinelli schrieb:
>>>> Wenn join() kein undef als Wert akzeptiert, dann müsste
>>>> das folgende ja auch einen Fehler ausgeben:
>>>> perl -e 'print join( " - ", ("a", "b", undef) );
>>>> Tut es aber nicht.
Stümmt!
>>> Join mag kein undef.
Wenn man die Reihen mit einem simplen /split/ zerlegt, ganz
offensichtlich doch. Allerdings werden dann bei der Ausgabe die
/abschließenden/ Semikola abgetrennt - was ja nicht weiter schlimm ist.
>Stimmt, dabei wär's noch gar nicht so spät am Abend gewesen.
>print join " - ", map { defined($_) ? $_ : "" } @werte;
^^^^^^^^^^^^^^^^^^^^^^^^^
Könntest du netterweise mal sagen, was genau das im Klar-Text bedeutet?
Bin leider nicht so firm in Sachen Perl.
Ansonsten tut das - keine /warnings/ mehr. :o)
So far,
--
Thomas Pothmann
PGP-Key on demand
Re: Text::ParseWords - chomp
am 14.05.2007 20:37:01 von hjp-usenet2
On 2007-05-14 16:23, Thomas Pothmann wrote:
> Christian Winter wrote:
>>Frank Seitz schrieb:
>>> Christian Winter wrote:
>>>> Join mag kein undef.
>
> Wenn man die Reihen mit einem simplen /split/ zerlegt, ganz
> offensichtlich doch.
Nein. In dem Fall enthält das Array schlicht und einfach kein undef.
Join mag dann zwar immer noch kein undef, aber es bekommt auch keines
und ist daher zufrieden.
hp
--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | hjp@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
Re: Text::ParseWords - chomp
am 14.05.2007 21:05:31 von Christian Winter
Thomas Pothmann schrieb:
> Christian Winter wrote:
>
>> Frank Seitz schrieb:
>>> Christian Winter wrote:
>>>> Hermann Martinelli schrieb:
>
>>>>> Wenn join() kein undef als Wert akzeptiert, dann müsste
>>>>> das folgende ja auch einen Fehler ausgeben:
>
>>>>> perl -e 'print join( " - ", ("a", "b", undef) );
>
>>>>> Tut es aber nicht.
>
> Stümmt!
>
>>>> Join mag kein undef.
>
> Wenn man die Reihen mit einem simplen /split/ zerlegt, ganz
> offensichtlich doch. Allerdings werden dann bei der Ausgabe die
> /abschließenden/ Semikola abgetrennt - was ja nicht weiter schlimm ist.
Was aber das Verhalten von join() nicht verändert, sondern nur
die Daten, die es zu sehen bekommnt :)
>> Stimmt, dabei wär's noch gar nicht so spät am Abend gewesen.
>> print join " - ", map { defined($_) ? $_ : "" } @werte;
> ^^^^^^^^^^^^^^^^^^^^^^^^^
> Könntest du netterweise mal sagen, was genau das im Klar-Text bedeutet?
> Bin leider nicht so firm in Sachen Perl.
join is ja bekannt, map führt den Code in geschweiften Klammern
für jedes Element der übergebenen Liste aus und gibt die Ergebnisse
wieder als Liste zurück. Dabei wird der aktuelle Wert wie in einer
foreach-Schleife in $_ abgelegt. Der Term in den geschweiften
Klammer ist ein Entweder-Oder-Ausdruck, d.h. wenn die Bedingung
vor dem Fragezeichen wahr ist, benutze den Wert vor dem Doppel-
punkt, ansonsten den danach.
Der Ausdruck rattert also alle Elemente von @werte ab und sieht bei
jedem nach ob er definiert ist. Wenn ja wird der Wert selbst
verwendet, ansonsten der leere String. Am Schluß wird die ganze
Liste an Werten dann mit wie gehabt mit join konkateniert.
Viele Grüße
-Christian
Re: Text::ParseWords - chomp
am 15.05.2007 08:35:17 von Ferry Bolhar
Christian Winter:
> map führt den Code in geschweiften Klammern
> für jedes Element der übergebenen Liste aus und gibt die Ergebnisse
> wieder als Liste zurück. Dabei wird der aktuelle Wert wie in einer
> foreach-Schleife in $_ abgelegt.
wobei nicht unerwähnt bleiben soll, dass $_ dann zu einem _Alias_ auf
das jeweilige Arrayelement wird (und nicht etwa zu einer Kopie). Das
heißt, dass sich Änderungen an $_ auf das jeweilige Element und somit
auf das ganze Array auswirken:
my @y = qw(1 2 3 4);
my @x = map {++$_} @y;
print "@x"; # Gibt 2 3 4 5 aus
Ich weiß schon, dass das hier nicht gebraucht wird, aber ich wollte es
dennoch erwähnen, denn es ist eine der interessantesten Funktionen
von map - und eine der gefährlichsten, wenn man - wie ich in meinen
Perl-Anfangszeiten - nicht darüber Bescheid weiß!
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: Text::ParseWords - chomp
am 15.05.2007 09:22:01 von Wolf Behrenhoff
Ferry Bolhar schrieb:
> Christian Winter:
>
>> map führt den Code in geschweiften Klammern
>> für jedes Element der übergebenen Liste aus und gibt die Ergebnisse
>> wieder als Liste zurück. Dabei wird der aktuelle Wert wie in einer
>> foreach-Schleife in $_ abgelegt.
>
> wobei nicht unerwähnt bleiben soll, dass $_ dann zu einem _Alias_ auf
> das jeweilige Arrayelement wird (und nicht etwa zu einer Kopie). Das
> heißt, dass sich Änderungen an $_ auf das jeweilige Element und somit
> auf das ganze Array auswirken:
>
> my @y = qw(1 2 3 4);
> my @x = map {++$_} @y;
> print "@x"; # Gibt 2 3 4 5 aus
Ich glaube, du möchtest eher darauf hinweisen, dass auch ein
print "@y";
ebenfalls 2 3 4 5 ausgibt! Wenn man das nicht möchte, muss man eben
statt ++$_ einfach $_+1 schreiben.
Wolf
Re: Text::ParseWords - chomp
am 15.05.2007 11:16:53 von Frank Seitz
Wolf Behrenhoff wrote:
[map ändert ursprüngliche Liste]
> Wenn man das nicht möchte, muss man eben
> statt ++$_ einfach $_+1 schreiben.
Darum ging es nicht, sondern darum, überhaupt zu wissen,
dass eine Änderung von $_ auf die ursprüngliche Liste durchschlägt.
foreach, map, grep sind da gleichermaßen "gefährlich".
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Text::ParseWords - chomp
am 15.05.2007 11:29:07 von Wolf Behrenhoff
Frank Seitz schrieb:
> Wolf Behrenhoff wrote:
>
> [map ändert ursprüngliche Liste]
>
>> Wenn man das nicht möchte, muss man eben
>> statt ++$_ einfach $_+1 schreiben.
>
> Darum ging es nicht, sondern darum, überhaupt zu wissen,
> dass eine Änderung von $_ auf die ursprüngliche Liste durchschlägt.
> foreach, map, grep sind da gleichermaßen "gefährlich".
Eben.
Und darum nutzt es wenig, zu Demonstrationszwecken die neue Liste
auszugeben. Man muss die ursrüngliche Variable, hier @y, ausgeben, um zu
demonstrieren, dass sich Änderungen an $_ darauf ausgewirkt haben!
Ich gehe davon aus, dass Ferry auch eigentlich print "@y" schreiben wollte.
Wolf
Re: Text::ParseWords - chomp
am 15.05.2007 11:32:10 von Frank Seitz
Wolf Behrenhoff wrote:
> Eben.
>
> Und darum nutzt es wenig, zu Demonstrationszwecken die neue Liste
> auszugeben. Man muss die ursrüngliche Variable, hier @y, ausgeben, um zu
> demonstrieren, dass sich Änderungen an $_ darauf ausgewirkt haben!
>
> Ich gehe davon aus, dass Ferry auch eigentlich print "@y" schreiben wollte.
Ja, das war ein Flüchtigkeitsfehler. War mir auch aufgefallen.
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Text::ParseWords - chomp
am 15.05.2007 16:19:46 von Ferry Bolhar
Wolf Behrenhoff:
> > my @y = qw(1 2 3 4);
> > my @x = map {++$_} @y;
> > print "@x"; # Gibt 2 3 4 5 aus
>
> Ich glaube, du möchtest eher darauf hinweisen, dass auch ein
>
> print "@y";
>
> ebenfalls 2 3 4 5 ausgibt!
Natürlich. Es wird das _ursprüngliche_ Array modifiziert.
Das ist ja das besondere an map (und auch an grep!).
Danke für den Hinweis!
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: Text::ParseWords - chomp
am 21.05.2007 12:36:53 von Ingo Menger
On 12 Mai, 16:06, t...@lycos.de (Thomas Pothmann) wrote:
> Tach!
>
> Ich beackere seit geraumer Zeit eine Datenbank (temporär CSV), in der d=
as
> letzte Feld nur sporadisch mit einem Wert belegt ist. Erst jetzt ist mir
> aufgefallen, daß bei Verwendung des o.g. Moduls folgendes Phänomen
> auftritt: Ich bekomme /warnings/ für alle Datensätze, in denen das
> letzte Feld leer ist und das somit mit einem /;/ endet: "Use of
> uninitialized value at ..."
>
> Hier mal ein Beispielschnipsel:
>
> #! /usr/bin/perl -w
> #
> use strict;
> use Text::ParseWords;
> #
> my $TheLine =3D "";
> my @array =3D ();
> #
> while () {
> $TheLine =3D $_;
> chomp ($TheLine);
> #
> @array =3D "ewords(";", 1, $TheLine);
> $TheLine =3D join (";", @array);
> print STDOUT "$TheLine\n";}
>
> __DATA__
> "ene";"mene";"miste";
> "es";"rappelt";"in";"der"
> "kiste";"jawoll";"ja";
>
> Bislang war ich der Auffassung, daß /chomp/ im Hinblick auf die
> Zeilenende-Konventionen system-übergreifend funktioniert.
>
> Zitat aus Ulrich Cuber: Linux Scripting, S. 331 (Perl-Programmierung):
> "Die Funktion chomp () stellt eine brauchbare Variante von chop () dar.
> Sie ist auf Zeilenenden spezialisiert. Und dies unter Berücksichtigung
> der verschiedenen Konventionen der Betriebs-Systeme."
>
> Ist aber offensichtlich nicht der Fall.
Doch. for my $os (qw(Windows Unix)) gilt: unter $os werden $os-
Zeilenenden entfernt.
> Die CSV-Dateien kommen von der
> Windows-Plattform,
Es gilt allerdings nicht: unter Unix werden Windows-Zeilennenden
entfernt.
Im Einzelfall kann man störende carriage returns "\r" extra wegwerfen:
chomp();
s/\r//g; # falls file von Windows kommt und das Script unter UNIX
läuft
Re: Text::ParseWords - chomp
am 22.05.2007 19:14:03 von hjp-usenet2
On 2007-05-21 10:36, Ingo Menger wrote:
> On 12 Mai, 16:06, t...@lycos.de (Thomas Pothmann) wrote:
>> Zitat aus Ulrich Cuber: Linux Scripting, S. 331 (Perl-Programmierung):
>> "Die Funktion chomp () stellt eine brauchbare Variante von chop () dar.
>> Sie ist auf Zeilenenden spezialisiert. Und dies unter Berücksichtigung
>> der verschiedenen Konventionen der Betriebs-Systeme."
>>
>> Ist aber offensichtlich nicht der Fall.
>
> Doch. for my $os (qw(Windows Unix)) gilt: unter $os werden $os-
> Zeilenenden entfernt.
Jein. Es werden (wenn man nicht an $/ herumgespielt hat) die Zeilenenden
entfernt, die man bekommt, wenn man ein Textfile dieses Betriebssystems
im Textmodus liest.
Unter Unix ist das Zeilenende in Files "\x{0A}", und das wird beim Lesen
unverändert übernommen. $/ ist daher "\x{0A}";
Unter Windows ist das Zeilenende in Files "\x{0D}\x{0A}", das wird beim
Lesen im Textmodus aber in "\x{0A}" umgewandelt. $/ ist daher ebenfalls
"\x{0A}".
Sowohl unter Unix als auch Windows entfernt chomp also per Default
"\x{0A}".
Man kann (seit Perl 5.8) allerdings auch unter Unix Perl dazu bringen,
ebenso wie unter Windows die Zeilenenden im IO-Layer zu konvertieren.
Dazu muss man den IO-Layer ':crlf' entweder beim Ãffnen des Files oder
unmittelbar danach mittels binmode angeben. Das geht auch global mittels
use open.
hp
--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | hjp@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"