12

Perl で固定長レコードを読み取る最良の方法は何ですか? 次のようなファイルを読むことを知っています:

ABCDE 302
DEFGC 876

できます

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

しかし、読み取り/アンパックでこれを行う方法はありませんか?

4

5 に答える 5

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 はオプションですが、体系的で対称的です。これの利点の 1 つは、それを検証できることです$blank eq " "

于 2009-01-02T17:06:20.433 に答える
12

更新: 決定的な回答については、以下の Jonathan Leffler の回答を参照してください。

これを 2 つのフィールドだけに使用することはありませんが ( pack / unpackを直接使用します)、20 または 50 ほどのフィールドにはParse::FixedLengthを使用したいと思います(ただし、偏っています)。例 (例) (更新: また、read($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";
于 2009-01-02T20:53:44.717 に答える
6

レコードごとに 2 つの 5 文字フィールドの 10 文字レコードがあるとします。

open(my $fh, "<", $filename) or die $!;
while(read($fh, $buf, 10)) {
  ($field1, $field2) = unpack("A5 A5", $buf);
  # ... do something with data ...
}
于 2009-01-02T18:28:37.803 に答える
-1

これを行う別の方法を次に示します。

while (<FILE>)
{
    chomp;
    if (/^([A-Z]{5}) ([0-9]{3})$/)
    {
        $key = $1;
        $value = $2;
    }
}
于 2013-02-19T19:20:47.840 に答える
-2

レコードとフィールドが固定長であるかどうかに関係なく、フィールドが均一な区切り文字 (スペースやコンマなど) で区切られている場合は、アンパックするよりも簡単に分割機能を使用できます。

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

分割のドキュメントを参照してください。引数リストと区切り文字パターンの形式には、便利なバリエーションがあります。

于 2009-01-02T17:31:46.607 に答える