当行具有可变数量的字段时,Perl嵌套哈希

时间:2014-09-26 15:17:50

标签: perl

我有来自Unix命令的行,但每行都有可变数量的字段 我想创建嵌套哈希。我怎样才能做到这一点。

我使用split ('[\|=]' $line)

拆分每一行

命令数据:

node:server1|name=server1
node:server1|status=up
node:server1|state=running
node:server1|initial_incarnation=1
node:server1|os_status=up
node:server1|summary=ok



node:server2|subnet:X.Y.Z.0|name=X.Y.Z.0
node:server2|subnet:X.Y.Z.0|route_id=1
node:server2|subnet:X.Y.Z.0|status=up
node:server2|subnet:X.Y.Z.0|ip_monitor=off

node:server1|interface:lan1|ip_address:X.Y.Z.17|name=X.Y.Z.17
node:server1|interface:lan1|ip_address:X.Y.Z.17|netmask=255.255.248.0
node:server1|interface:lan1|ip_address:X.Y.Z.17|subnet=X.Y.Z.0
node:server1|interface:lan1|ip_address:X.Y.Z.17|route_id=1
node:server1|interface:lan1|ip_address:X.Y.Z.17|heartbeat=true

node:server1|interface:lan2|ip_address:X.Y.Z.17|name=X.Y.Z.17
node:server1|interface:lan2|ip_address:X.Y.Z.17|netmask=255.255.248.0
node:server1|interface:lan2|ip_address:X.Y.Z.17|subnet=X.Y.Z.0
node:server1|interface:lan2|ip_address:X.Y.Z.17|route_id=1
node:server1|interface:lan2|ip_address:X.Y.Z.17|heartbeat=true

我想完成如下的HOH:

%hoh = (
    'node:server1' => {
        name   => 'server1',
        status => 'up',
        ...,
        summary          => 'ok',
        'interface:lan1' => {
            'ip_address:X.Y.Z.17' => {
                name    => 'X.Y.Z.17',
                netmask => '255.255.248.0',
            },
            ...,
        },
        'nterface:lan2' => {
            'ip_address:X.Y.Z.18' => {
                name    => 'X.Y.Z.18',
                netmask => '255.255.248.0',
            },
            ...,
        },
    },
    'node:server2' => ...,
);

2 个答案:

答案 0 :(得分:1)

这样的事情应该这样做:

use warnings;
use strict;
use Data::Dumper;

my %href;

while (my $line = <DATA>) { # or wherever you're reading from
    next if $line =~ /^\s*$/;
    chomp $line;

    my @parts = split /\|/, $line;
    my ($subkey, $value) = split /=/, pop @parts;

    my $r = \%href;
    for my $part (@parts) {
        $r->{$part} = {} unless defined $r->{$part}; # perl < v5.10
        # if you're using perl >= v5.10, you can do this instead:
        # $r->{part} //= {};

        $r = $r->{$part};
    }
    $r->{$subkey} = $value;
}

print Dumper(\%href);

答案 1 :(得分:1)

改编自Re: hashes recursively(来自PerlMonks的超级搜索):

use warnings;
use strict;

my %data;
while (<DATA>) {
    next unless /\S/;
    chomp;
    Define(\%data, split /[|=]/)
}

use Data::Dumper;
$Data::Dumper::Sortkeys=1;
$Data::Dumper::Indent=1;
print Dumper(\%data);

sub Define { # value returned not used above,
             # but can be useful for some other cases
    my $href = shift;
    my $key = shift or return $href;
    defined ( $href -> { $key } ) or $href -> { $key } = {};
    my $value = shift or return $href -> { $key };
    @_ and return Define( $href -> { $key }, $value, @_ );
    return $href -> { $key } = $value;
}

__DATA__
node:server1|interface:lan1|ip_address:X.Y.Z.17|name=X.Y.Z.17
node:server1|interface:lan1|ip_address:X.Y.Z.17|netmask=255.255.248.0
node:server1|interface:lan1|ip_address:X.Y.Z.17|subnet=X.Y.Z.0
node:server1|interface:lan1|ip_address:X.Y.Z.17|route_id=1
node:server1|interface:lan1|ip_address:X.Y.Z.17|heartbeat=true

node:server1|interface:lan2|ip_address:X.Y.Z.17|name=X.Y.Z.17
node:server1|interface:lan2|ip_address:X.Y.Z.17|netmask=255.255.248.0
node:server1|interface:lan2|ip_address:X.Y.Z.17|subnet=X.Y.Z.0
node:server1|interface:lan2|ip_address:X.Y.Z.17|route_id=1
node:server1|interface:lan2|ip_address:X.Y.Z.17|heartbeat=true

输出:

$VAR1 = {
  'node:server1' => {
    'interface:lan1' => {
      'ip_address:X.Y.Z.17' => {
        'heartbeat' => 'true',
        'name' => 'X.Y.Z.17',
        'netmask' => '255.255.248.0',
        'route_id' => '1',
        'subnet' => 'X.Y.Z.0'
      }
    },
    'interface:lan2' => {
      'ip_address:X.Y.Z.17' => {
        'heartbeat' => 'true',
        'name' => 'X.Y.Z.17',
        'netmask' => '255.255.248.0',
        'route_id' => '1',
        'subnet' => 'X.Y.Z.0'
      }
    }
  }
};