2009-01-02 10 views
11

Was ist der beste Weg, um einen Datensatz fester Länge in Perl zu lesen. Ich weiß, dass eine Datei lesen wie:Wie lese ich Datensätze fester Länge in Perl?

ABCDE 302 
DEFGC 876 

I

tun kann
while (<FILE>) { 
    $key = substr($_, 0, 5); 
    $value = substr($_, 7, 3); 
} 

aber nicht da ist ein Weg, dies zu tun mit Lese-/entpacken?

Antwort

12

Update: Für die endgültige Antwort, Antwort unter Jonathan Leffler sehen.

Ich würde dies nicht nur für zwei Felder verwenden (I pack/unpack direkt verwenden würde), aber für 20 oder 50 oder so Felder Ich mag Parse::FixedLength zu verwenden (aber ich bin voreingenommen). Z.B. (Für Beispiel) (Update: auch, können Sie $/und <> als Alternative zu lesen ($ fh, $ buf, $ buf_length) ... siehe unten):

use Parse::FixedLength; 

my $pfl = Parse::FixedLength->new([qw(
    key:5 
    blank:1 
    value:3 
)]); 
# Assuming trailing newline 
# (or add newline to format above and remove "+ 1" below) 
my $data_length = $pfl->length() + 1; 

{ 
    local $/ = \$data_length; 
    while(<FILE>) { 
    my $data = $pfl->parse($_); 
    print "$data->{key}:$data->{value}\n"; 
    # or 
    print $data->key(), ":", $data->value(), "\n"; 
    } 
} 

Es gibt einige, ähnliche Module, die packen/entpacken "freundlicher" machen (Siehe den "Siehe auch" -Abschnitt von Parse :: FixedLength).

Update: Wow, das sollte eine alternative Antwort sein, nicht die offizielle Antwort ... nun, da es das ist, was es ist, sollte ich einige von Jonathan Lefflers geradlinigeren Code einbeziehen, der wahrscheinlich so ist sollte in der Regel tun es (pack/unpack docs und Jonathan Leffler Knoten siehe unten):

$_ = "ABCDE 302"; 
my($key, $blank, $value) = unpack "A5A1A3"; 
18
my($key, $value) = unpack "A5 A3"; # Original, but slightly dubious 

Wir brauchen beide die Optionen auf der unpack Manpage zu überprüfen (und insbesondere die pack manuelle Seite).

Da die Packung Bediener entfernt Leerzeichen sind, kann Ihr Beispiel als codiert werden:

my($key, $value) = unpack "A6A3"; 

Alternativ (dies ist Perl, so TMTOWTDI):

my($key, $blank, $value) = unpack "A5A1A3"; 

Die 1 ist optional, aber systematische und symmetrisch. Ein Vorteil davon ist, dass Sie diese $blank eq " " validieren können.

-2

Unabhängig davon, ob Ihre Datensätze und Felder fester Länge sind, können Sie, wenn die Felder durch einheitliche Trennzeichen getrennt sind (z. B. ein Leerzeichen oder Komma), die Split-Funktion einfacher als das Entpacken verwenden.

my ($field1, $field2) = split//; 

Suchen Sie in der Dokumentation nach Split. Es gibt nützliche Variationen in der Argumentliste und im Format des Begrenzermusters.

+1

Wenn alle Feldwerte sind kleiner als die feste Breite (obwohl Dies ist in seinem Beispiel nicht der Fall), wird die Zeichenfolge Auch für die nachgestellten Leerzeichen wird das getrennt, was falsch ist.Wenn die Feldwertlängen alle identisch sind, dann sind Sie richtig, es gibt keinen Unterschied zwischen –

+2

und der festen Breite. Es ist keine Frage der Feldlänge. Wenn Felder einen signifikanten Leerraum haben können, können Sie nicht auf Whitespaces aufgeteilt werden. Das ist einer der Punkte von Feldern mit fester Länge. :) –

6

Angenommen 10 Zeichen Aufzeichnungen von zwei fünf Zeichenfelder pro Datensatz:

open(my $fh, "<", $filename) or die $!; 
while(read($fh, $buf, 10)) { 
    ($field1, $field2) = unpack("A5 A5", $buf); 
    # ... do something with data ... 
} 
+0

Dies ist die einfachste Antwort – joshlk

-1

Hier ist noch eine weitere Möglichkeit, es zu tun:

while (<FILE>) 
{ 
    chomp; 
    if (/^([A-Z]{5}) ([0-9]{3})$/) 
    { 
     $key = $1; 
     $value = $2; 
    } 
} 
Verwandte Themen