2010-11-24 6 views
1

ich eine Textdatei, die wie folgt aussieht:Perl - Start von bestimmten Zeile zu lesen, und nur die erste Spalte der Zeile für bekommen, bis zum Ende

Line 1 
Line 2 
Line 3 
Line 4 
Line 5 
filename2.tif;Smpl/Pix & Bits/Smpl are missing. 

Es gibt 5 Linien, die immer gleich sind, und in der 6. Zeile möchte ich anfangen, Daten zu lesen. Beim Lesen der Daten wird jede Zeile (beginnend mit Zeile 6) durch Semikola begrenzt. Ich brauche nur den ersten Eintrag jeder Zeile (beginnend in Zeile 6).

Zum Beispiel:

Line 1 
Line 2 
Line 3 
Line 4 
Line 5 
filename2.tif;Smpl/Pix & Bits/Smpl are missing. 
filename4.tif;Smpl/Pix & Bits/Smpl are missing. 
filename6.tif;Smpl/Pix & Bits/Smpl are missing. 
filename8.tif;Smpl/Pix & Bits/Smpl are missing. 

Ausgang wäre erwünscht:

filename2.tif 
filename4.tif 
filename6.tif 
filename8.tif 

Ist dies möglich, und wenn ja, wo soll ich anfangen?

+1

Es ist möglich. Hast du schon einen Code? – aschepler

+0

Ja und nein. Nicht dafür - aber ich habe mehr als 300 Codezeilen, in die ich dies umzusetzen versuche. Es ist im Grunde eine neue Funktion, die ich implementieren möchte, um Dateien aus einer Textdatei zu verarbeiten, die bereits existiert. – drewrockshard

+0

Die Antwort auf alle Fragen beginnend, * "In Perl, ¿kann ich tun ...?" * Ist ** "¡Ja!" ** Die Antwort auf einige von diesen geht jedoch weiter mit ** "Ja, aber ...". ** – tchrist

Antwort

4

Das die 'Autosplit' Perl verwendet (oder 'awk') Modus:

perl -n -F'/;/' -a -e 'next if $. <= 5; print "$F[0]\n";' < data.file 

See 'perlrun' und 'perlvar'.


Wenn Sie dies in einer Funktion zu tun, die ein Datei-Handle und eine Anzahl von Zeilen zu überspringen gegeben wird, dann werden Sie nicht die ‚Autosplit‘ -Modus Perl.

sub skip_N_lines_read_column_1 
{ 
    my($fh, $N) = @_; 
    my $i = 0; 
    my @files =(); 
    while (my $line = <$fh>) 
    { 
     next if $i++ < $N; 
     my($file) = split /;/, $line; 
     push @files, $file; 
    } 
    return @files; 
} 

Dies initialisiert eine Schleife liest Linien, die erste von ihnen N-Skipping, dann die Linienaufspaltung und nur das erste Ergebnis zu erfassen. Diese Linie mit my($file) = split... ist subtil; Die Klammern bedeuten, dass der Split einen Listenkontext hat, also generiert er eine Liste von Werten (anstatt einer Anzahl von Werten) und weist der Variable den ersten zu. Wenn die Klammern weggelassen würden, würden Sie einem Listenoperator einen skalaren Kontext geben, sodass Sie die Anzahl der Felder in der geteilten Ausgabe erhalten würden, die $file zugewiesen ist - nicht was Sie benötigen. Der Dateiname wird an das Ende des Arrays angehängt, und das Array wird zurückgegeben. Da der Code das Dateihandle nicht geöffnet hat, wird es nicht geschlossen. Eine alternative Schnittstelle würde den Dateinamen (anstelle eines geöffneten Dateihandles) in die Funktion übergeben. Sie würden dann die Datei in der Funktion öffnen und schließen und sich um die Fehlerbehandlung kümmern.

Und wenn Sie die Hilfe mit dem Öffnen der Datei benötigen, etc, dann:

use Carp; 

sub open_skip_read 
{ 
    my($name) = @_; 
    open my $fh, '<', $name or croak "Failed to open file $name ($!)"; 
    my @list = skip_N_lines_read_column_1($fh, 5); 
    close $fh or croak "Failed to close file $name ($!)"; 
    return @list; 
} 
+0

+1. Beste Antwort, wirklich. Ich muss den Perl-Teil meines Gehirns retten :) –

+0

Wie würde ich das in ein Skript schreiben, und nicht in eine Befehlszeile, und von einem geöffneten Datei-Handle einer Datei lesen, die bereits existiert? – drewrockshard

+0

@ Jonathan: Es macht mir Angst, dass Perl weiß, Ihre Schrägstrichbegrenzer um den Separator zu verschlingen. Ich wusste es nicht! – tchrist

2

Ein bisschen hässlich, aber, lesen Sie die Dummy-Zeilen aus und spalten Sie dann auf; für den Rest von ihnen.

my $logfile = '/path/to/logfile.txt'; 

open(FILE, $logfile) || die "Couldn't open $logfile: $!\n"; 

for (my $i = 0 ; $i < 5 ; $i++) { 
    my $dummy = <FILE>; 
} 

while (<FILE>) { 
    my (@fields) = split /;/; 
    print $fields[0], "\n"; 
} 

close(FILE); 
+0

Dies kann so geschrieben werden: 'my @dummy; @dummy [0..4] = ; map {($ a) = split /; /; drucken $ a, "\ n"} ; '. –

+0

Was ist, wenn ich versuche, von einer Datei einzulesen, aber nicht von der Befehlszeile. Ich habe eine Datei, die an einem relativen Speicherort ist (so kann ich es beispielsweise mit logfile.txt aufrufen). Ich habe Probleme beim Einlesen, bis jetzt läuft mein Code ständig in einer While-Schleife und ich muss CTRL + C draus machen. – drewrockshard

+1

@Diego: * Por desgracia, * das wird nicht funktionieren, weil Sie nur Listenkontext für den "readline" -Operator in Ihrer Slice-Zuweisung geliefert haben, was die Eingabe erschöpfte. Die restlichen Zeilen wurden verworfen. – tchrist

2
#!/usr/bin/env perl 
# 
# name_of_program - what the program does as brief one-liner 
# 
# Your Name <[email protected]_host.TLA> 
# Date program written/released 
################################################################# 

use 5.10.0; 

use utf8; 
use strict; 
use autodie; 
use warnings FATAL => "all"; 

# ⚠ change to agree with your input: ↓ 
use open ":std" => IN => ":encoding(ISO-8859-1)", 
        OUT => ":utf8"; 
# ⚠ change for your output: ↑ — *maybe*, but leaving as UTF-8 is sometimes better 

END {close STDOUT} 

our $VERSION = 1.0; 

$| = 1; 

if (@ARGV == 0 && -t STDIN) { 
    warn "reading stdin from keyboard for want of file args or pipe"; 
} 

while (<>) { 
    next if 1 .. 5; 
    my $initial_field = /^([^;]+)/ ? $1 : next; 
    # ╔═══════════════════════════╗ 
    # ☞ your processing goes here ☜ 
    # ╚═══════════════════════════╝ 
} continue { 
    close ARGV if eof; 
} 

__END__ 
+0

Leute, ich bin immer noch verloren - ** neu in Perl **. Ich habe bereits eine Datei, die alles enthält. Ich muss nur die Datei in meinem Skript öffnen, die ersten 5 Zeilen überspringen und die erste Spalte jeder Zeile nach der fünften Zeile ausgeben. – drewrockshard

+0

@drewsrockhard: Das ist mein Programm. Versuch es. – tchrist

+0

Können Sie ein Beispiel zeigen, wie Sie dies ausführen und wo Sie Ihre "Eingabedatei" ablegen können? – drewrockshard