在Perl中读取固定长度记录的最佳方法是什么。我知道要读取如下文件:
ABCDE 302
DEFGC 876
我能做到
while (<FILE>) {
$key = substr($_, 0, 5);
$value = substr($_, 7, 3);
}
但是没有办法用read / unpack做到这一点吗?
答案 0 :(得分:18)
my($key, $value) = unpack "A5 A3"; # Original, but slightly dubious
我们都需要查看unpack手册页(以及更具体的pack手册页)中的选项。
由于A pack运算符删除了尾随空白,因此您的示例可以编码为:
my($key, $value) = unpack "A6A3";
或者(这是Perl,TMTOWTDI):
my($key, $blank, $value) = unpack "A5A1A3";
1是可选的,但系统且对称。这样做的一个优点是您可以验证$blank eq " "
。
答案 1 :(得分:12)
更新:有关最终答案,请参阅下面的Jonathan Leffler的答案。
我不会将它仅用于两个字段(我直接使用pack / unpack),但对于20或50个左右的字段,我喜欢使用Parse::FixedLength(但我有偏见)。例如。 (对于你的例子)(更新:同样,你可以使用$ /和&lt;&gt;作为读取的替代方法($ fh,$ 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";
}
}
有一些类似的模块使打包/解包更“友好”(参见Parse :: FixedLength的“另请参阅”部分)。
更新:哇,这本来是一个替代答案,而不是正式答案......好吧,因为它就是这样,我应该包括Jonathan Leffler的一些更直接的代码,这可能是你应该怎么做的通常这样做(请参阅下面的pack / unpack文档和Jonathan Leffler的节点):$_ = "ABCDE 302";
my($key, $blank, $value) = unpack "A5A1A3";
答案 2 :(得分:6)
假设每条记录有两个五个字符字段的10个字符记录:
open(my $fh, "<", $filename) or die $!;
while(read($fh, $buf, 10)) {
($field1, $field2) = unpack("A5 A5", $buf);
# ... do something with data ...
}
答案 3 :(得分:-1)
这是另一种方法:
while (<FILE>)
{
chomp;
if (/^([A-Z]{5}) ([0-9]{3})$/)
{
$key = $1;
$value = $2;
}
}
答案 4 :(得分:-2)
无论您的记录和字段是否为固定长度,如果字段由统一分隔符(例如空格或逗号)分隔,您可以比解包更容易使用拆分函数。
my ($field1, $field2) = split / /;
查找文档以进行拆分。参数列表和分隔符模式的格式有很多有用的变体。