2

以下に示すように、データを含むdata.txtがあります。3 つの定数 ID 100、200、300 を持つ約 100 の名前があり、それぞれに 32 のデータ値があります。

NAME: xyz
ID: 100
DATA: 10 15 99 13 ...
ID: 200
DATA: 23 45 78 90..
ID: 300
DATA: 45 67 89 56
NAME: abc
ID: 100
DATA: 2 4 787 8..
ID: 200
DATA: 12 14 17..
ID: 300
DATA: 45 34 22..

このデータを次のような別のファイルに書き込む必要があります

xyz_100, xyz_200,xyz_300,abc_100,...
10     , 23     , 45     ,2
15     , 45     ,67       ,4

値を格納するためにハッシュを作成しましたが、現在、私のコードは最初の 2 つのエントリを上書きし、最後のエントリを格納しています。最初の 2 つのエントリも保存するにはどうすればよいですか。コードを簡略化できるかどうか教えてください。

#!/usr/local/bin/perl
use diagnostics;
use strict;
use warnings;

my @avar_names;
my %record;

local $/ = '';
open my $fh, '<', 'datalog.dat' or die "failed: $!";
while (<$fh>) {
  chomp;
   my %avar;
   while (/^([A-Z:]+):\s*(.*)/mg) {
      $avar{$1} = $2;
   }
   my $avar_name = "$avar{NAME}_$avar{ID}";

   push @avar_names, $avar_name;
   $record{$avar_name} = $avar{DATA};

use Data::Dumper;
print Dumper \%record;
}
4

2 に答える 2

2

一貫性の問題があります。このlocal行は最初のwhileで NAME/ID データ全体を全体として処理しますが (while(//mg)ループのおかげで)、コードはそのままでは行ごとの処理を想定しています。

簡単にすることをお勧めします。ファイル行を 1 つずつ処理し、現在の行の正規表現のおかげで、「名前/ID」のペア (ID はデータの可能性があります) を識別します。

それが機能するためには、ファイルの最後の行から取得した最後の NAME/ID 参照を追跡する必要があるため、 onに対してローカルである%avar必要はありません。while<$fh>

@avar_names配列は使用されません。

最後に、結果のレコードを最後に印刷したい (と思いました) が、それはあなたの選択です。

これは、上記のものだけを変更しようとしたプログラムです。

#!/usr/local/bin/perl
use diagnostics;
use strict;
use warnings;

my @avar_names;
my %record;

#local $/ = ''; ## commented out
open my $fh, '<', 'datalog.dat' or die "failed: $!";

my %avar; ## moved here

while (<$fh>) {
   chomp;
   if (m/^([A-Z]+):\s*(.*)/) {  ## if, not a while
      $avar{$1} = $2;

      ## ensure we have at least our 3 keys, process only if we met DATA
      if (exists($avar{NAME}) && exists($avar{ID}) && exists($avar{DATA}) && $1 eq 'DATA') { 
         my $avar_name = "$avar{NAME}_$avar{ID}";

         push @avar_names, $avar_name;  ## not used
         $record{$avar_name} = $avar{DATA};
      }
   }
}

use Data::Dumper;
print Dumper \%record;

出力:

$VAR1 = {
          'xyz_100' => '10 15 99 13 ...',
          'xyz_300' => '45 67 89 56',
          'abc_200' => '12 14 17..',
          'abc_300' => '45 34 22..',
          'abc_100' => '2 4 787 8..',
          'xyz_200' => '23 45 78 90..'
        };
于 2013-05-31T06:20:01.147 に答える
1

次のようなものが必要です。

my @avars;
# ... some code
while (<$fh>) {
  # more code
  my %curr;
  while (/^([A-Z:]+):\s*(.*)/mg) {
    $curr->{$1} = $2;
  }
  if (%curr) {
     push @avars, \%curr;
     my $avar_name = "$curr{NAME}_$curr{ID}";
     push @avar_names, $avar_name;
     $record{$avar_name} = $avar{DATA};
  }
  # ....
于 2013-05-31T05:28:01.917 に答える