如何读取Perl中的固定长度记录?

如何读取Perl中的固定长度记录?,perl,fixed-length-record,Perl,Fixed Length Record,在Perl中读取固定长度记录的最佳方法是什么。我知道如何读取以下文件: ABCDE 302 DEFGC 876 我能行 while (<FILE>) { $key = substr($_, 0, 5); $value = substr($_, 7, 3); } while(){ $key=substr($\ 0,5); $value=substr($,7,3); } 但是,有没有一种方法可以通过读取/解包来实现这一点 my($key, $value) = unpac

在Perl中读取固定长度记录的最佳方法是什么。我知道如何读取以下文件:

ABCDE 302
DEFGC 876
我能行

while (<FILE>) {
   $key = substr($_, 0, 5);
   $value = substr($_, 7, 3);
}
while(){
$key=substr($\ 0,5);
$value=substr($,7,3);
}
但是,有没有一种方法可以通过读取/解包来实现这一点

my($key, $value) = unpack "A5 A3";    # Original, but slightly dubious
我们都需要在手册页面(尤其是手册页面)查看选项

由于A pack运算符删除了尾随空格,因此您的示例可以编码为:

my($key, $value) = unpack "A6A3";
或者(这是Perl,所以是TMTOWTDI):


1是可选的,但具有系统性和对称性。这样做的一个优点是,无论记录和字段的长度是否固定,都可以验证
$blank eq”“

,如果字段由统一的分隔符(如空格或逗号)分隔,则使用拆分功能比解包更容易

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

查找有关拆分的文档。在参数列表和分隔符模式的格式上有一些有用的变体。

假设10个字符的记录,每个记录有两个5个字符的字段:

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

open(my$fh),更新:有关最终答案,请参阅下面的Jonathan Leffler的答案

我不会只对两个字段(我会直接使用/使用)使用此选项,但我会对20或50个左右的字段使用此选项(但我有偏见)。例如(例如)(更新:您也可以使用$/和作为阅读($fh,$buf,$buf_length)的替代选项,请参见下文):


还有另一种方法:

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

如果任何字段值小于固定宽度(尽管在他的示例中并非如此),字符串也将被拆分为尾随空格,这是错误的。如果字段值长度都相同,则您是正确的,分隔宽度和固定宽度之间没有区别。这不是字段长度的问题。如果字段可以有有效的空白,则不能拆分空白。这是固定长度的点之一字段:)这是最简单的答案
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";
  }
}
$_ = "ABCDE 302";
my($key, $blank, $value) = unpack "A5A1A3";
while (<FILE>)
{
    chomp;
    if (/^([A-Z]{5}) ([0-9]{3})$/)
    {
        $key = $1;
        $value = $2;
    }
}