2009-01-02 58 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; 
    } 
}