2010-12-11 36 views
2

我有一個大的數據集基本上可以歸結爲這樣的工作:優雅解析硬數據在Perl

my $input = q(
<foo>111</foo> 
<foo>222</foo> 
<foo>333</foo> 
<foo></foo> 
<foo>555</foo> 
); # new-lines are either CR+LF, LF, or CR 

根據上面的例子,讓我們假設以下限制實際上是:

  • 總是會有5行數據。
  • 每行中的數據都包含在一個標記中,如<foo>...</foo>
  • 數據將不包含嵌套標籤。
  • 所有行都使用相同的標記(例如foo)來封裝其數據。

最終,採取上述作爲數據源,我想用這個東西類似於結束:

my %values = (
    one => '111', 
    two => '222', 
    three => '333', 
    four => '', 
    five => '555' 
); 

這是我的嘗試:

my @vals = $input =~ m!<foo>(.*?)</foo>!ig; 

if (scalar @vals != 5) { 
    # panic 
} 

my %values = (
    one => shift @vals, 
    two => shift @vals, 
    three => shift @vals, 
    four => shift @vals, 
    five => shift @vals 
); 

這是我想要的,但它看起來很醜並且不很靈活。不幸的是,這是我現在所能做的最好的,因爲我是Perl新手。

因此,考慮到上述限制,這樣做更優雅的方式是什麼?

回答

3

首先,再看看:

my %values = (
    one => '111', 
    two => '222', 
    three => '333', 
    four => '', 
    five => '555' 
); 

該數據結構相關聯用一塊數據的整數。但是已經有一個內置的數據結構可以達到同樣的目的:數組。因此,使用數組。而不是編寫$values{ one },你會寫$values[ 0 ],整數和數據值之間的映射將是透明的。

如果密鑰以外的東西不是整數,你可以這樣做:

use strict; use warnings; 

my @keys = qw(a b c d e); 

my $input = q(
<foo>111</foo> 
<foo>222</foo> 
<foo>333</foo> 
<foo></foo> 
<foo>555</foo> 
); # new-lines are either CR+LF, LF, or CR 

my %values; 

# hash slice 
@values{ @keys } = $input =~ m{ <foo> (.*?) </foo>}gix; 

use YAML; 
print Dump \%values; 

輸出:

--- 
a: 111 
b: 222 
c: 333 
d: '' 
e: 555
+0

的最後一個例子是很整潔。謝謝! – jnaturelle 2010-12-11 17:35:40

+0

最後一個例子*是*有點整齊,但假設有一個固定數量的鍵。如果你希望它更靈活,並且在你繼續生成密鑰的時候,將它映射到一個大小相同的列表(並將該列表分配給散列)。 'map'和'grep'是朋友。 :) – fennec 2010-12-11 17:43:22

2

哦,類似這樣的事情嗎?

use Number::Spell; 
$input =~ s|<(?:/)?foo>||g; 
my @lines = grep { $_ } split "\n", $input; # grep for blank lines 
my $i = 0; 
my %hash = map { spell_number($i++) => $_ } @lines; 

嗯,我可以做得更好。

use Number::Spell; 
my $i = 0; 
my %hash = map { s|<(?:/)?foo>||g; $_ ? spell_number($i++) => $_ :() } 
      split "\n", $input; 

。哎呀,有一個@lines而不是$輸入inna第二個片段。 請謹慎使用;我只輸入了這段代碼;我沒有寫過單元測試。

4

合併兩個數組到一個散列:

my @keys = qw/one two three/; 
my @values = qw/alpha beta gamma/; 

my %hash; 
@hash{@keys} = @values;