Datei-Durchlauf in Perl

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
uname
Beiträge: 12403
Registriert: 03.06.2008 09:33:02

Datei-Durchlauf in Perl

Beitrag von uname » 20.12.2013 10:11:35

Ich versuche gerade in Perl eine Datei zu durchlaufen und möchte einige Zeilen "überspringen". Um das an einem Beispiel klar zu machen soll eine Datei welche untereinander die Zahlen 1 bis 8 hat nur die geraden Zahlen ausgeben. Im Normalfall sind die Dateien jedoch evtl. so groß, dass ich es mir nicht leisten kann die Daten in ein Array zu laden. Somit würde ich gerne das Programm 1 in Programm 2 überführen. Aktuell nutze ich z.B. Variablen welche mir die Zeilen zählen. Gerne würde ich aber innerhalb irgendeiner Schleife auch mal zwei Zeilen einlesen bzw. einfach eine Zeile überspringen. Geht das irgendwie?

Programm 1:
(funktioniert ganz gut bei "kleinen" Dateien)

Code: Alles auswählen

#! /usr/bin/perl  
$file="datei.txt";
open (READ,"$file");
@a=<READ>;
close (READ); 
chomp (@a);
$i = 1;
while ($i <= $#a)
{
  print $a[$i] . "\n";
  $i = $i + 2;
}
Programm 2:
(hier benötige ich eine Lösung, statt irgendwas mit "if" einzubauen (also nur gerade Zeilen ausgeben) würde ich gerne mal eine Zeile lesen ohne sie zu verarbeiten)

Code: Alles auswählen

#! /usr/bin/perl  
$file="datei.txt";
open(FILE,"$file");
while (<FILE>)
{
  $ent = $_;
  print $ent;
}

syssi
Beiträge: 2951
Registriert: 24.12.2010 16:50:59
Lizenz eigener Beiträge: MIT Lizenz
Wohnort: Rheinland

Re: Datei-Durchlauf in Perl

Beitrag von syssi » 20.12.2013 10:33:40

Sowas sieht man haeufig:

Code: Alles auswählen

#! /usr/bin/perl  
$file="datei.txt";
open(FILE,"$file");
$ent = "";
while (<FILE>)
{
  $previous = $ent;
  $ent = $_;
  print $ent;
}

Benutzeravatar
lilith2k3
Beiträge: 107
Registriert: 30.05.2007 00:28:05

Re: Datei-Durchlauf in Perl

Beitrag von lilith2k3 » 20.12.2013 22:50:00

Also nur gerade Zeilen ausgeben geht auch anders:

Code: Alles auswählen

perl -ne 'print if !($.%2)' datei.txt
Zu deutsch:
starte Perl, lese Datei zeilenweise ein und tue folgendes mit den Zeilen: Wenn Zeilennummer ($.) gerade, dann Print.

Ansonsten lohnt sich: http://perlmaven.com/open-and-read-from-files mal anzugucken.

Cae
Beiträge: 6349
Registriert: 17.07.2011 23:36:39
Wohnort: 2130706433

Re: Datei-Durchlauf in Perl

Beitrag von Cae » 21.12.2013 00:48:13

Wenn das awk waere, suchst du getline:

Code: Alles auswählen

$ seq 5 | awk '{print; getline}'
1
3
5
$ 
(fuer gerade Zahlen koennte man {getline; print} schreiben, also andersrum, aber das druckt bei ungerader Gesamtzeilenzahl die letzte (ungerade) Zeile trotzdem.) Keine Ahnung, ob Perl auch sowas kann. Vermutlich schon.

Sonst wuerd' ich den Modulo-Vorschlag von oben etwas aufbohren:

Code: Alles auswählen

$ seq 5 | perl -ne '$.%2&&print'
1
3
5
$ 
bzw. fuer gerade Zahlen

Code: Alles auswählen

$ seq 5 | perl -ne '$.%2||print'
2
4
$ 
Allerdings ist Modulo bei grossen Zahlen teuer, da kann's effizienter sein, ein binaeres Flag zu verwenden.

Gruss Cae
If universal surveillance were the answer, lots of us would have moved to the former East Germany. If surveillance cameras were the answer, camera-happy London, with something like 500,000 of them at a cost of $700 million, would be the safest city on the planet.

—Bruce Schneier

Benutzeravatar
lilith2k3
Beiträge: 107
Registriert: 30.05.2007 00:28:05

Re: Datei-Durchlauf in Perl

Beitrag von lilith2k3 » 21.12.2013 01:31:13

Ich werfe mal

Code: Alles auswählen

seq 15 | perl -ne '$.&1||print'
in die Runde ;)

Benutzeravatar
Meillo
Moderator
Beiträge: 9238
Registriert: 21.06.2005 14:55:06
Wohnort: Balmora
Kontaktdaten:

Re: Datei-Durchlauf in Perl

Beitrag von Meillo » 26.12.2013 12:25:26

Die awk-Variante geht auch einfacher:

Code: Alles auswählen

seq 15 | awk 'NR%2'     # ungerade
seq 15 | awk 'NR%2==0'  # gerade
(Das funktioniert, weil die Standardaktion bei awk ein `print' ist.)

Du kannst auch jederzeit weitere Regeln hinzufuegen, wie z.B. die geraden Zeilen ausgeben und zudem die Zeile 7 mit einem ``foo'' davor:

Code: Alles auswählen

seq 15 | awk 'NR%2==0; NR==7 {print "foo"; print}'

Oder mit sed, falls du das Modulo-Rechnen verhinden willst:

Code: Alles auswählen

seq 15 | sed 'n;d'     # ungerade
seq 15 | sed -n 'n;p'  # gerade
Use ed once in a while!

Antworten