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

И это та часть, которая повреждает, потому что я не 't действительно хочу глубоко скопировать весь %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; 

    } 
}