Loeschen leere Zeilen (newline)
Lev Benenson
- perl
0 Dennis Plöger0 klaus0 Dennis Plöger0 Calocybe0 Kai Diefenbach0 klaus0 Kai Diefenbach0 klaus0 Calocybe
Hi, alle,
es gibt ein Problem.
Es gibt eine Datei, bestehend aus vielen Zeilen. Einige Zeilen bestehen nur aus Newline (leere Zeilen). Diese Zeilen möchte ich mit einen Perlscript loeschen. Bis jetzt waren alle meine Versuche erfolgslos.
Fuer jede Hilfe waere ich dankbar.
Lev Benenson
Hi Lev!
es gibt ein Problem.
*Schock*
Es gibt eine Datei, bestehend aus vielen Zeilen. Einige Zeilen bestehen nur aus Newline (leere Zeilen). Diese Zeilen möchte ich mit einen Perlscript loeschen. Bis jetzt waren alle meine Versuche erfolgslos.
Wann kommt das Problem?? ;-)
Gut, ich würde es so machen, dass ich die Datei zeilenweise abarbeite und in eine temp-Datei schreibe. Wenn eine leere Zeile vorkommt (regEx dafür wäre glaube ich /^$/), schreibt er die nicht in die Temp, ansonsten schreibt er alles.
Am Schluß dann die alte löschen und die Temp-Datei umbenennen.
-- Diese Lösung ist allerdings für Dateien mit ständigem Zugriff etwas schwierig, weil je nach Größe natürlich große Ladezeiten auftreten.
Bis denne,
Dennis
hallo,
oder Du machst es so:
open(IN, $dateiname);
@Zeilen = <IN>;
close(IN);
open(OUT,">$dateiname");
foreach $zeile (@zeilen)
{
chomp $zeile; #entfernt das NEWLINE
$zeile =~ s/\s*$//; #optional entfern leerzeichen am ende vom string
next unless $zeile; #weiter wenn Zeile leer ist
print OUT "$zeile\n";
}
close(OUT);
Grüße
Klaus
Hallöle!
... so geht es auch (ist ja nur 'n anderer Programmierstil ;-)), man muss allerdings immer noch sagen, dass es bei größeren Dateien zu Langwierigkeiten kommt!
'Ne andere Lösung wüßt ich aber so auch nicht...
Bis denne,
Dennis
Hi Klaus!
open(IN, $dateiname);
Wie immer: open(IN, "<$dateiname") die("Can't open $dateiname for reading because: $!");
@Zeilen = <IN>;
close(IN);
open(OUT,">$dateiname");
foreach $zeile (@zeilen)
{
chomp $zeile; #entfernt das NEWLINE
$zeile =~ s/\s*$//; #optional entfern leerzeichen am ende vom string
next unless $zeile; #weiter wenn Zeile leer ist
Vorsicht: Das schlaegt auch an, wenn in der Zeile eine einzige 0 steht (wird dann als die Zahl 0 interpretiert, und das ist logisch false). Daher:
next unless length($zeile); #weiter wenn Zeile leer ist
print OUT "$zeile\n";
}
close(OUT);
So long
Hallo Lev/Klaus,
ich würde es so machen:
hallo,
oder Du machst es so:
open(IN, $dateiname);
Rückgabewert testen
open IN, $dateiname or die "$!";
open OUT, ">$dateiname" or die "$!";
@Zeilen = <IN>;
close(IN);
open(OUT,">$dateiname");
In diesem Fall besteht IMHO kein Grund, die gesamte Datei in ein Array zu lesen. Dies kann sehr Speicherintensiv werden.
foreach $zeile (@zeilen)
{
chomp $zeile; #entfernt das NEWLINE
$zeile =~ s/\s*$//; #optional entfern leerzeichen am ende vom
»» string
next unless $zeile; #weiter wenn Zeile leer ist
print OUT "$zeile\n";
}
close(OUT);
while (<IN>) {
print OUT unless /^$/;
}
close IN;
close OUT;
Grüße
Klaus
Gruß
Kai
hallo,
open IN, $dateiname or die "$!";
open OUT, ">$dateiname" or die "$!";
ja ja, ich war schlampig.
In diesem Fall besteht IMHO kein Grund, die gesamte Datei in ein Array zu lesen. Dies kann sehr Speicherintensiv werden.
es ist immer die Frage, was gerade besser ist, nur mit einer Datei arbeiten oder mit zweien. wenn die Datei gecht groß ist, dann ist es zweifellos besser, mit einer zwischendatei zu arbeiten.
ein zweiter Grund könnte sein, daß die Datei auch von anderen Prozessen, z.B. dem Webserver immer gebraucht wird. dann ist es besser die Datei kurz vorher erst zu entfernen und die zwsichendatei umzubenennen.
Mit einer Zwischendatei würde ich das Array auch weglassen:
while (<IN>) {
»» print OUT unless /^$/;
}
auch hier wieder Vorischt:
eine leerzeile ist nicht wirklich leer, und <IN> bringt dann ein '\n' daher,also
while (<IN>)
{
chomp;
print OUT unless /^$/;
}
aber, um das ganze abzukürzen, sollte der geneigte Programmierer sich die Datei ansehen, und dann entscheiden, welchen Weg er beschreiten will.
weil wie sagt's Larry so treffen: TMTOWTDI
grüße
Klaus
Hallo Klaus,
[...]
while (<IN>) {
»» print OUT unless /^$/;
}
auch hier wieder Vorischt:
eine leerzeile ist nicht wirklich leer, und <IN> bringt dann ein '\n' daher,also
while (<IN>)
{
chomp;
Nur der Vollstaendigkeit halber:
ein chomp ist hier nicht noetig, weil der Zeilenende-Anker $, (u.a.) in Perl, auf das Ende des gesamten Strings, sowie vor einem Newline am Ende des Strings passt - und zweiteres ist ja hier der Fall.
print OUT unless /^$/;
}
[...]
grüße
Klaus
Gruss
Kai
ein chomp ist hier nicht noetig, weil der Zeilenende-Anker $, (u.a.) in Perl, auf das Ende des gesamten Strings, sowie vor einem Newline am Ende des Strings passt - und zweiteres ist ja hier der Fall.
Hallo Kai,
mein Irrtum, 'tschuldige.
sollte wieder mal das Kleingeschriebene lesen.
schönen Abend noch,
klaus
Hi!
Nur der Vollstaendigkeit halber:
ein chomp ist hier nicht noetig, weil der Zeilenende-Anker $, (u.a.) in Perl, auf das Ende des gesamten Strings, sowie vor einem Newline am Ende des Strings passt - und zweiteres ist ja hier der Fall.
Nein, das gilt nur, wenn der Modifier m angegeben wird, also
print OUT unless /^$/m;
Ohne diesen matcht ein ^ wirklich nur den Anfang des Strings (nicht den einer Zeile innerhalb des Strings) und $ nur das Ende des Strings. Siehe perldoc perlre -> Abschnitt Description.
So long
Hallo Calobyte,
Hi!
print OUT unless /^$/m;
Ohne diesen matcht ein ^ wirklich nur den Anfang des Strings (nicht den einer Zeile innerhalb des Strings) und $ nur das Ende des Strings. Siehe perldoc perlre -> Abschnitt Description.
Sorry, *das* ist falsch, denn perldoc perlre sagt:
By default, the ^'' character is guaranteed to match only the beginning of the string, the
$'' character only the end *(or before the newline at the end)*
[...]
You may, however, wish to treat a string as a multi-line buffer, such that the ^'' will match after any newline within the string, and
$'' will match before any newline. At the cost of a little more overhead, you can do this by using the /m modifier on the pattern match operator
[...]
Das meint: bei /m passt $ auf jedes \n, auch mitten im String.
Vergl. auch: Regular Expressions, O'Reilly, J. Friedl S. 237 (ff)
So long
Gruss
Kai
Re Hi!
By default, the
^'' character is guaranteed to match only the beginning of the string, the
$'' character only the end *(or before the newline at the end)*
Mmh, tatsaechlich, soweit hab ich gar nicht gelesen (ganz oben bei der ersten Erklaerung von m stands naemlich nicht). Offen gesagt, finde ich diese Sonderbehandlung ein bisschen doof (weil unlogisch). Gibt es eine Moeglichkeit, das abzustellen?
So long
Hi Ray,
Re Hi!
By default, the
^'' character is guaranteed to match only the beginning of the string, the
$'' character only the end *(or before the newline at the end)*Mmh, tatsaechlich, soweit hab ich gar nicht gelesen (ganz oben bei der ersten Erklaerung von m stands naemlich nicht). Offen gesagt, finde ich diese Sonderbehandlung ein bisschen doof (weil unlogisch). Gibt es eine Moeglichkeit, das abzustellen?
Nein, "$" passt immer (mind.) auf Ende und "\n" vor Ende. Ist IMHO kein Bug sondern ein Feature, da sich genau o.g. Aufgaben
effizient loesen lassen.
Wenn explizit das Ende des Strings gemeint ist, kann man
(?!\n)$ #(?!\n) -> "naechstes Zeichen, darf kein \n sein"
benutzen.
So long
Gruss
Kai
Re Hi!
Nein, "$" passt immer (mind.) auf Ende und "\n" vor Ende. Ist IMHO kein Bug sondern ein Feature, da sich genau o.g. Aufgaben
effizient loesen lassen.
Nun ja, das faellt wohl unter Geschmackssache. Nicht jede Vereinfachung ist wirklich hilfreich im Programmierhandwerk, weil sie meist an anderer Stelle wieder Probleme mit sich bringt. Deshalb mag ich Perl im Grunde genommen auch nicht so sehr, weil es viele Dinge uebertrieben stark vereinfacht und einem damit die Kontrolle entzieht.
Wenn explizit das Ende des Strings gemeint ist, kann man
(?!\n)$ #(?!\n) -> "naechstes Zeichen, darf kein \n sein"
Ich hab in perlre jetzt noch \z gefunden, das man anstelle von $ einsetzen kann. Nicht schoen, weil gewaltige Umstellung (allerorten wird immer nur $ benutzt), aber wenn's hilft.
So long