将值存储在哈希中

时间:2014-10-08 02:32:52

标签: perl parsing reference procedural-programming

目前使用perl来解析由多个Sections组成的配置文件,而这些配置文件又可以包含多个定义。我的实际文件有一个完全不同的主题,但我的解析器也会解析这个例子:

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!",
  ),
);

2 个答案:

答案 0 :(得分: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,
         },
}

答案 1 :(得分: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;

    }
}