将文本文件解析为嵌套数据结构

时间:2018-05-15 00:12:51

标签: perl data-structures

这是我的文字档案:

animal, cola, husband, 36 
animal, wilma, wife, 31
animal, pebbles, kid, 4
brutal, george, husband, 41
brutal, jane, wife, 39
brutal, elroy, kid, 9
cosa, homer, husband, 34
cosa, marge, wife, 37
cosa, bart, kid, 11

这就是我想要的数据结构:

%HASH = (
    animal  => [
        { name => "cola",    role => "husband", age  => 36, },
        { name => "wilma",   role => "wife",    age  => 31, },
        { name => "pebbles", role => "kid",     age  =>  4, },
    ],
    brutal  => [
        { name => "george",  role => "husband", age  => 41, },
        { name => "jane",    role => "wife",    age  => 39, },
        { name => "elroy",   role => "kid",     age  =>  9, },
    ],
    cosa  => [
        { name => "homer", role => "husband", age => 34, },
        { name => "marge", role => "wife",    age => 37, },
        { name => "bart",  role => "kid",     age => 11, },
    ],
);

我有一些代码,但我无法将它们组装成一个连贯的脚本。我只希望有人帮助我定义这个结构并理解它。

2 个答案:

答案 0 :(得分:2)

  1. 将每一行解析为哈希。
  2. 从哈希中删除键列。
  3. 根据键列将哈希推送到数组中。
  4. 代码:

    use strict;
    use warnings;
    
    use Data::Dumper;
    
    my %hash;
    my @columns = qw(category name role age);
    
    while (<DATA>) {
        chomp;
        my %temp;
        @temp{@columns} = split(/\s*,\s*/);
    
        my $key = delete($temp{category});
        push(@{$hash{$key}}, \%temp);
    }
    
    print Dumper(\%hash);
    
    __DATA__
    animal, cola, husband, 36
    animal, wilma, wife, 31
    animal, pebbles, kid, 4
    brutal, george, husband, 41
    brutal, jane, wife, 39
    brutal, elroy, kid, 9
    cosa, homer, husband, 34
    cosa, marge, wife, 37
    cosa, bart, kid, 11
    

    输出:

    $VAR1 = {
              'cosa' => [
                          {
                            'name' => 'homer',
                            'age' => '34',
                            'role' => 'husband'
                          },
                          {
                            'name' => 'marge',
                            'age' => '37',
                            'role' => 'wife'
                          },
                          {
                            'name' => 'bart',
                            'age' => '11',
                            'role' => 'kid'
                          }
                        ],
              'brutal' => [
                            {
                              'name' => 'george',
                              'age' => '41',
                              'role' => 'husband'
                            },
                            {
                              'name' => 'jane',
                              'age' => '39',
                              'role' => 'wife'
                            },
                            {
                              'name' => 'elroy',
                              'age' => '9',
                              'role' => 'kid'
                            }
                          ],
              'animal' => [
                            {
                              'name' => 'cola',
                              'age' => '36',
                              'role' => 'husband'
                            },
                            {
                              'name' => 'wilma',
                              'age' => '31',
                              'role' => 'wife'
                            },
                            {
                              'name' => 'pebbles',
                              'age' => '4',
                              'role' => 'kid'
                            }
                          ]
            };
    

答案 1 :(得分:2)

您显示的数据结构有一个关于它的关键规则:哈希值中的值只能是标量。

因此,要将多值变量与键相关联,请使用对该变量的引用,此处为arrayref。如果该数组中的值需要比标量更复杂,则再次使用引用,这里是hashref。因此每个键的值是一个arrayref,其元素是hashrefs。

然后,您需要学习如何访问结构中更深层的元素。这也不是很复杂:取消引用它们然后你可以像使用数组或散列一样使用它们。

所有这些都在perldsc中,需要明确perlreftut。完整参考是perlref

在你的问题中使用它时

use warnings;
use strict;

use Data::Dump qw(dd);

my $file = 'data.txt';
open my $fh, '<', $file or die "Can't open $file: $!";

my %result;

while (<$fh>) {
    chomp;
    my ($key, $name, $role, $age) = split /\s*,\s*/;

    push @{$result{$key}}, { name => $name, role => $role, age => $age };   
}

dd \%result;

这将打印正确的数据结构。请注意使用Data::Dump查看复杂的数据结构。最常见的模块是Data::Dumper,还有其他模块。

上面的split使用正则表达式/\s*,\s*/作为分隔符,因此可以用逗号分隔行,可选地用空格包围。其默认值用于要拆分的字符串,即$_

请注意,我们不必“添加密钥”或使用它们的arrayref值,因为这是通过 autovivification 完成的。例如,请参阅this pagethis page以及this page。 这是一个复杂的功能,如果误用就会咬人,所以请仔细阅读。

如果数组或散列被列为数组的“元素”,它们会被“展平” - 它们的元素与所有其他给定元素合并,整个聚合列表用于填充数组,我们用所有这些元素得到一个数组。所以

my @ary = 1..3;
my %hash = (a => 10, b => 20);
# Most likely an error:
my @all = (5, @ary, %hash, 100);  #--> (5, 1, 2, 3, a, 10, b, 20, 100)

其中键值对可以以任何顺序出现,因为哈希本质上是无序的。

相反,我们引用数组和哈希并写入

my @all = (5, \@ary, \%hash, 100);

现在@ary%hash的内容保持个性,可以根据需要恢复。