2013-05-31 62 views
2

我有data.txt與數據如下所示。我有大約100個名字,3個常量ID爲100,200,300,每個名稱都有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 

我建立一個哈希存儲的值,但現在我的代碼覆蓋前兩個條目,並存儲在最後一項。我怎樣才能保存前兩個條目,請讓我知道我是否可以簡化代碼。

#!/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; 
} 

回答

2

有一個一致性的問題:local線使第一過程完整的名稱/ ID數據作爲一個整體(當時,由於該循環),但是它所期望的代碼是逐行處理的。

我建議使用簡單的方法:逐一處理文件行,爲每一個文件行確定一個「NAME/ID」對(ID可能是DATA),這要歸功於當前行的正則表達式。

爲了這工作,%avar需要是本地的while<$fh>,因爲它跟蹤的最後一個名稱/ ID的引用它從文件的最後幾行了。

@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..' 
     }; 
+1

感謝您的回覆。轉儲不打印任何東西。是範圍外的%記錄的值?如果我更改爲打印\%阿瓦爾而不是\%記錄其打印最後一個值abc_300。 – user1336997

+0

糟糕。它實際上是'$ 1',而不是'if(exist ...)'行中的$ 2' ...應該始終相信複製粘貼與手動更改;-) –

+0

perfecto !!萬分感謝! – user1336997

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}; 
    } 
    # .... 
+1

感謝您的答覆。你的意思是@avars或%avars?我可以解決數組的負值嗎?$ avars [-1] ?? – user1336997

+0

我的意思是@avars,你可以用'-1'來指代最後一個(推送)的項目 – perreal

+0

錯誤顯示:嘗試修改不可創建的數組值,在script3.pl中修改下標-1 第18行,<$fh>塊1 (1) (F)您試圖使數組值彈簧存在,並且 下標可能是負數,即使從數組 的末尾開始倒數。 – user1336997