2014-10-08 102 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; 

    } 
}