2009-01-02 72 views
11

在Perl中讀取固定長度記錄的最佳方式是什麼?我知道,如同閱讀文件:如何讀取Perl中的固定長度記錄?

ABCDE 302 
DEFGC 876 

我可以做

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

,但不是有沒有辦法與讀取做到這一點/解壓?

回答

12

更新:對於明確的答案,請參見下面喬納森·萊弗勒的答案。

我不會用這只是兩個字段(我會使用pack/unpack直接),但20個或50左右的領域我喜歡用Parse::FixedLength(但我有偏見)。例如。 (您的例子)(更新:也可以使用$ /和<>作爲替代閱讀($跳頻,$ BUF,$ buf_length)...見下文):

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"; 
    } 
} 

有一些使得pack/unpack更加「友好」的類似模塊(參見Parse :: FixedLength的「See Also」部分)。

更新:哇,這是爲了替代答案,而不是正式答案......好吧,既然它是什麼,我應該包括一些喬納森·萊弗勒的更直接的代碼,這可能是你通常應做(見pack/unpack文檔及以下喬納森·萊弗勒的節點):

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

我們都需要在unpack手冊頁(更具體地說,pack手冊頁)檢查出的選項。

由於A組操作者除去尾隨空白,你的例子可以被編碼爲:

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

可選地(這是Perl中,所以TMTOWTDI):

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

的1是可選的,但系統的並對稱。這樣做的一個好處是你可以驗證那$blank eq " "

-2

無論您的記錄和字段是否爲固定長度,如果這些字段由統一分隔符(例如空格或逗號)分隔,則可以比解壓縮更容易使用拆分功能。

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

查閱拆分文檔。參數列表和分隔符格式的格式有很多有用的變化。

+1

如果任何字段值是小於固定寬度(雖然這在他的例子中不是這樣),字符串會被分割爲尾隨空格,這是錯誤的。如果字段值長度全部相同,那麼你是正確的,分隔和固定寬度之間沒有區別 – 2009-01-02 21:00:22

+2

這不是字段長度的問題。如果字段可以有很大的空白,你不能分割空白。這是固定長度字段的一個要點。 :) – 2009-01-03 00:32:11

6

假設每條記錄兩塊五字符字段的10個字符的記錄:

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

這裏是另一種方式來做到這一點:

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