在哈希中打印ARRAY的内容

时间:2017-03-17 06:50:29

标签: perl

如何在哈希中打印数组内容?我正在使用Dumper,因此您可以看到我正在解析的数据。

print Dumper \%loginusers;

 for my $key ( keys %loginusers ) {
        my $value = $loginusers{$key};
        print "$key => $value\n";
 } 


 printf "%s %-32s %-18s\n","User","Hostname","Since";

输出

$VAR1 = {
          'server1.localdomain.com:8080' => [
',                                                                                 'user=user1
'                                                                                  'since=2017-03-10 13:53:27
                                                                                 ]
        };

server1.localdomain.com:8080 => ARRAY(0x1584748)
User Hostname                         Since

正如你所看到的那样,有一个ARRAY(0x1584748)并且我不知道如何从哈希中获取该值。

我希望看到的是:

User  Hostname                         Since
user1 server1.localdomain.com:8080     2017-03-10 13:53:27

非常感谢能够提供帮助的人。

更新: 因此,在尝试此操作后,查看数据的外观:

foreach my $key (keys %loginusers) 
{
    print "For $key:\n";
    print "\t|$_|\n" for @{$loginusers{$key}};
}

输出如下:

For server1.localdomain.com:8080:
|       |user=user1
|       |since=2017-03-10 13:53:27

更新: 尝试在代码中添加这些:

foreach my $key (keys %loginusers)
{
    my @fields =
        map { s/^\s*//; s/\s*\Z//; s/\s*\n\s*/ /g; $_ }
        grep { /\S/ }
            @{$loginusers{$key}};

    print "For $key:\n";
    print "$_\n" for @fields;
}

并使用两个示例代码:

printf "%-8s %-32s %s\n", qw(User Hostname Since);
foreach my $key (keys %loginusers)
{
    my %field = map { /\s*(.*?)=\s*(.*)/ } @{$loginusers{$key}};
    my ($host, $rgsender, $port) = split /:/, $key;
    printf "%-8s %-32s %s\n", $field{user}, $host, $field{since};
}


my $newusers;
for my $host ( keys %loginusers ) {
    local $/ = "\r\n"; #localised "input record separator" for the "chomp"
    %{$newusers->{$host}} = map { chomp; split /=/,$_,2 } @{$loginusers{$host}};
}
undef %loginusers;  #not needed anymore
#print "NEW STRUCTURE: ", Dumper $newusers;

printline( qw(User Hostname Since) );
printline($newusers->{$_}{user}, $_, $newusers->{$_}{since}) for (keys %$newusers);

sub printline { printf "%-8s %-32s %-18s\n", @_; }

以下是结果:

User     Hostname                          Since
user1    server1.localdomain.com:8080      2017-03-10 13:53:27
User     Hostname                          Since
user1    server1.localdomain.com:8080      2017-03-10 13:53:27

2 个答案:

答案 0 :(得分:2)

哈希值是标量,可以参考。这就是我们构建复杂数据结构的方式。你的显然有阵列参数,所以你需要取消引用它们。像

这样的东西
foreach my $key (keys %hash) {
    say "$key => @{$hash{key}}";
}

请参阅教程perlretut和有关数据结构的食谱perldsc

来自Dumper的奇怪输出表明值(或更差)周围可能存在前导/尾随空格,需要将其清除。在澄清之前,我将假设像

这样的数据
'server1.localdomain.com:8080' => ['user=user1', 'since=2017-03-10 13:53:27']

为了获得所需的输出,您需要拆分每个元素

printf "%-8s %-32s %s\n", qw(User Hostname Since);
foreach my $key (keys %hash)
{
    my ($user, $since) = map { /=\s*(.*)/ } @{$hash{$key}};

    printf "%-8s %-32s %s\n", $user, $key, $since;
}

对于每个值,我们取消引用它并通过map传递。 map块中的代码(应用于每个元素)将拉出=之后的代码。给定数据,第一个是用户,第二个是时间戳。由于这是一个数组(而不是哈希),我假设订单是固定的。如果没有,请从=的两边获取字符串并分析它们以查看哪一个去哪里。或者更好地使用哈希

my %field = map { /\s*(.*?)=\s*(.*)/ } @{$hash{$key}};

其中.*?.*的非贪婪版本,直到第一个 =为止。然后打印为

printf "%-8s %-32s %s\n", $field{user}, $key, $field{since};

并且您不依赖于arrayref中的订单。请参阅answer by jm666,了解从一开始构建此内容的良好且一致的方法。

使用上面显示的哈希打印

User     Hostname                         Since
user1    server1.localdomain.com:8080     2017-03-10 13:53:27

我根据显示的数据使用了832宽度。为了更精确,有表格输出模块。如果您手动执行此操作,则需要预先处理并在键和/或值中找到每列的最长单词,然后在printf的第二遍中使用这些长度。

似乎Dumper被奇怪的数据搞糊涂了。看看我们做了什么

foreach my $key (keys %loginusers) 
{
    print "For $key:\n";
    print "\t|$_|\n" for @{$loginusers{$key}};
}

要清理您可以尝试的数据

foreach my $key (keys %loginusers) 
{
    my @fields = 
        map { s/^\s*//; s/\s*$//; s/\s*\R\s*/ /g; $_ } 
        grep { /\S/ } 
            @{$loginusers{$key}};

    print "For $key:\n";
    print "$_\n" for @fields;
}

grep获取输入列表并过滤掉其块内的代码评估为false的元素。这里我们至少需要一个非空格字符。然后它的输出进入map,删除所有前导和尾随空格,并用空格替换所有换行符。

答案 1 :(得分:2)

您的数据结构并不是很好。我会将它转换为更好的,使用:

#convert to better structure
my $newusers;
for my $host ( keys %loginusers ) {
        %{$newusers->{$host}} = map { chomp; split /=/,$_,2 } @{$loginusers{$host}};
}
undef %loginusers;      #the old not needed anymore
print "NEW STRUCTURE: ", Dumper $newusers;

转储现在看起来像:

NEW STRUCTURE: $VAR1 = {
          'server1.localdomain.com:8080' => {
                                              'user' => 'user1',
                                              'since' => '2017-03-10 13:53:27'
                                            }
        };

以上印刷后很简单:

printline( qw(User Hostname Since) );
printline($newusers->{$_}{user}, $_, $newusers->{$_}{since}) for (keys %$newusers);

sub printline { printf "%-8s %-32s %-18s\n", @_; }

对于解释,请阅读@ zdim的优秀答案(并接受他的回答:))

完整代码

use 5.014;
use warnings;
use Data::Dumper;

my %loginusers = (
'server1.localdomain.com:8080' => [
        "user=user1\r\n",   # you probably have the \r too
        "since=2017-03-10 13:53:27\r\n",
     ]
);
say "OLD STRUCTURE: ", Dumper \%loginusers;

#convert to better structure
my $newusers;
for my $host ( keys %loginusers ) {
    %{$newusers->{$host}} = map { s/[\r\n]//g; split /=/, $_, 2 } @{$loginusers{$host}}; #removes all \r and \n
} 
undef %loginusers;  #not needed anymore
say "NEW STRUCTURE: ", Dumper $newusers;

printline( qw(User Hostname Since) );
printline($newusers->{$_}{user}, $_, $newusers->{$_}{since}) for (keys %$newusers);

sub printline { printf "%-8s %-32s %-18s\n", @_; }

结果:

OLD STRUCTURE: $VAR1 = {
          'server1.localdomain.com:8080' => [
                                              'user=user1
',
                                              'since=2017-03-10 13:53:27
'
                                            ]
        };

NEW STRUCTURE: $VAR1 = {
          'server1.localdomain.com:8080' => {
                                              'user' => 'user1',
                                              'since' => '2017-03-10 13:53:27'
                                            }
        };

User     Hostname                         Since             
user1    server1.localdomain.com:8080     2017-03-10 13:53:27

修改

您的数据中可能还有\r。请参阅更新的代码。