2014-10-08 99 views
0

當前使用perl解析由多個部分組成的配置文件,該文件又可以由多個定義組成。我的實際文件有一個完全不同的話題,但我的解析器將解析這個例子中,太:將值存儲在散列表中

SECTION Foo 
HP 200 
ATT 50 Slap 
ATT 100 Kick 
DESC This is Foo. What is love? 

SECTION Bar 
HP 2 
ATT 1 Mumble 
DESC This is Bar. Baby don't hurt me! 

現在,我的解析器主要採用三個變量來存儲數據:

my %sections; 
my $parsedName; 
my %parsedVars; 

在閱讀SECTION Bar,它已填寫如下:

%sections =(); # empty 
$parsedName = "Foo"; 
%parsedVars = (
    "HP" => "200", 
    "ATT" => ("50 Slap","100 Kick"), 
    "DESC" => "This is Foo. What is love?", 
); 

我想你明白了。現在,%parsedVars字段的內容進行驗證,如果成功的話,整個事情被存儲到%sections,這是我的代碼使用的有:

use Storable qw(dclone); 
# (...) 
# Clone the Variables 
$sections{$parsedName} = dclone (\%parsedVars); 
# Prepare for next section 
$parsedName = getSectionName $currentLine; 
undef %parsedVars; 

這是傷害的一部分,因爲我不由於嚴格限制的運行時環境,我真的不想深入複製整個%parsedVars,並且我也不允許包含除strict以外的任何內容。

我覺得我應該從它的名字中分離哈希,並將它附加到$sections{$parsedName},但是我無法將我的頭圍繞如何完成。

# These hiccups aside, 
# my parser works fine, which is nice. 
# One completeness wide: 
# Result looks like this, no surprise! 

%sections = (
    "Foo" => (
    "HP" => "200", 
    "ATT" => ("50 Slap","100 Kick"), 
    "DESC" => "This is Foo. What is love?", 
), 
    "Bar" => (
    "HP" => "2", 
    "ATT" => "1 Mumble", 
    "DESC" => "This is Bar. Baby don't hurt me!", 
), 
); 

回答

1
use strict; 
use warnings; 

my %data; 
my $section; 

while (<DATA>) { 
    chomp; 
    next if /^\s*$/; 

    my ($key, $val) = split ' ', $_, 2; 

    if ($key eq 'SECTION') { 
     $section = $val; 
    } else { 
     push @{ $data{$section}{$key} }, $val; 
    } 
} 

# Collapse single element arrays: 
for (values %data) { 
    for (values %$_) { 
     $_ = $_->[0] if @$_ == 1; 
    } 
} 

use Data::Dump; 
dd \%data; 

__DATA__ 
SECTION Foo 
HP 200 
ATT 50 Slap 
ATT 100 Kick 
DESC This is Foo. What is love? 

SECTION Bar 
HP 2 
ATT 1 Mumble 
DESC This is Bar. Baby don't hurt me! 

輸出:

{ 
    Bar => { ATT => "1 Mumble", DESC => "This is Bar. Baby don't hurt me!", HP => 2 }, 
    Foo => { 
      ATT => ["50 Slap", "100 Kick"], 
      DESC => "This is Foo. What is love?", 
      HP => 200, 
     }, 
} 
0

一種方式將是聲明parsedVars爲包含散列引用代替散列一個標量。

當你開始解析每個部分:

$parsedVars = {}; # Allocate a new hash 

# store variables in the hash as you would before, but don't forget 
# to dereference the hash ref! 

# when finished parsing the section: 
$sections{$parsedName} = $parsedVars; 

另一種方法是在本地聲明其輸入爲輸入文件中的每個部分中的範圍內%parsedVars。這樣,每次你進入示波器,你都會得到一個新的哈希:

while (<FILE>) { 
    if (/^SECTION: (\w)+/) { 
     $parsedName=$1; 

     my %parsedVars; # this is the new hash, allocated 
         # each time a new section is allocated 

     # parse the variables as before, storing in the hash 

     # when done: 
     $sections{$parsedName} = \%parsedVars; 

    } 
}