【问题标题】:Perl :Not a HASH reference while creating nested hash from multi dimension arraysPerl:从多维数组创建嵌套哈希时不是哈希引用
【发布时间】:2019-06-01 20:44:01
【问题描述】:

我想通过读取由 -> 分隔的多维数组中的值来创建嵌套哈希,例如

Array 1: key1->key2->key3->value
Array 2: key1->key2->value
Array 3: key1->value

当键具有值和子键时,例如key2 有值,另一个键 key3 也有错误“不是 HASH 引用”。似乎它正在覆盖以前的哈希并考虑它的数组。

感谢您的帮助。我尝试使用 dumper 模块调试和打印变量和输出的值,发现它是 ARRAY 引用而不是哈希。

为了重现,请创建 .txt 文件,例如从 1 到 3.txt 在任何文件夹中,并且在这些文件中具有以下内容 1.txt : /TEST-TAG = ABC->DEF->fma->GHI/ 2.txt:/*TEST -TAG = ABC->DEF->fma 3.txt:/*TEST-TAG = ABC->DEF 然后在perl脚本中

#!/usr/bin/perl
use strict;
use warnings;

my @lines=`grep -R 'TEST-TAG =' <FOLDER where .txt files present>`;
my $hash;

#parse the lines which has pattern /\*TEST-TAG = ABC->DEF->fma->GHI\*/
foreach (@lines)
    {
    print "line is $_\n";

    my($all_cat) = $_ =~ /\=(.*)\*\//;
    print "all cat is $all_cat\n";

    my($testname) = $_ =~ /\/.*\/(.*)\./;
    print "testname is $testname\n";

    if (!$all_cat eq "") {
        $all_cat =~ s/ //g;
        my @ts = split(',', $all_cat);
        print "ts is @ts\n";
        my $i;
        foreach (@ts) {
            my @allfeat = split('->',$_);
            my $count =  scalar @allfeat;
            for ($i = 0; $i<$count; $i++) {
                my @temparr = @allfeat[$i..$count-1];
                print "temparr is @temparr\n";
                push @temparr, $testname;
                ToNestedHash($hash, @temparr);
            }
        }
    }
}
sub ToNestedHash {
        my $ref   = \shift;
        print "sandeep in ref $ref\n";
        print "sandeep in ref", ref($ref), "\n";
        my $h     = $$ref;
        print "sandeep h $h\n";
        my $value = pop;
        print "sandeep value is $value\n";
        print "sandeep array is @_\n";
        print "refrence",  ref($h), "\n";
        foreach my $i (@_) {
        print " before INDEX $i\n";
        print Dumper($ref);
        $ref =\$$ref->{ $i };
        print "after INDEX $i\n";
        print Dumper($ref);
        }
        if (!isinlist(\@{$$ref},$value)) {
            push @{$$ref}, $value;
        }
        return $h;
    }
    # If element exists in the list
    sub isinlist {
        my ($aref, $key) = ($_[0], $_[1]);

        foreach my $elem (@$aref){
            if ($elem eq $key) {
                return 1;
            }
        }
        return 0;
    }

我通过调试打印得到这个输出

line is File.txt:/*TEST-TAG = ABC->DEF->fma->GHI*/

all cat is  ABC->DEF->fma->GHI
testname is hmma_884_row_row_f16_f16
ts is ABC->DEF->fma->GHI
temparr is ABC DEF fma GHI
sandeep in ref REF(0x12a1048)
sandeep in refREF
sandeep h HASH(0x12a09a0)
sandeep value is hmma_884_row_row_f16_f16
sandeep array is ABC DEF fma GHI
refrenceHASH

REF
temparr is DEF fma GHI
sandeep in ref REF(0x12a1048)
sandeep in refREF
sandeep h HASH(0x12a09a0)
sandeep value is hmma_884_row_row_f16_f16
sandeep array is DEF fma GHI
refrenceHASH

REF
temparr is fma GHI
sandeep in ref REF(0x12a1048)
sandeep in refREF
sandeep h HASH(0x12a09a0)
sandeep value is hmma_884_row_row_f16_f16
sandeep array is fma GHI
refrenceHASH
Not a HASH reference at createjson.pl line 80.

有问题的线路是$ref =\$$ref-&gt;{$_} foreach (@_);

【问题讨论】:

  • Global symbol "@lines" requires explicit package name (did you forget to declare "my @lines"?) at .code.tio line 6.
  • 它在我的代码中,但我没有在示例中添加它。现在添加它。
  • if (!$all_cat eq "") 是一个奇怪的结构。当你实际上——以迂回的方式——测试真实性时,为什么要特意让它听起来好像你在测试空虚? !$all_cat 首先被评估,给出一个真值,该值将被转换为一个字符串(“1”或“”,空字符串)用于字符串比较。如果你想要真实,更清楚地说if ($all_cat),如果你想要非空,更清楚地说if ($all_cat ne '')
  • if (!$all_cat eq "") 不只是故意混淆if (length $all_cat) 的写法吗?
  • 另外,这里有很多非常令人困惑的参考语法。我不确定代码是由非常聪明的人编写的,还是没有他们想象的那么聪明的人编写的:-)

标签: perl hash


【解决方案1】:

睡在上面之后,我才意识到你想要更多地去哪里。您关心的问题是您试图将一些哈希值用作数组和哈希值。有两种方法可以处理这个问题。检测并处理它,或避免它。避免代码更简洁,所以我将展示它。

正如我在原始答案中提到的,我不确定您对“Dumper”行的想法,但 Data::Dump 可能是您正在使用的有用替代品,比 Data 更简单::我认为您设法使用的Dumper模块。我还选择仍然为您的文件名正则表达式提供替换,因为我仍然不想打扰完整的路径名。

#!/usr/bin/perl

use strict;
use warnings;

use Data::Dump;

my @lines = `grep -R 'TEST-TAG =' foo`;
my $hash;

$| = 1; # keep STDOUT and STDERR together

#parse the lines which has pattern /\*TEST-TAG = ABC->DEF->fma->GHI\*/
foreach (@lines) {
    print "line is $_\n";

    my($all_cat) = $_ =~ /\=(.*)\*\//;
    print "all cat is $all_cat\n";

    my($testname) = $_ =~ /(?:.*\/)?(.*?)\./;
    print "testname is $testname\n";

    if ($all_cat ne "") {
        $all_cat =~ s/ //g;
        my @ts = split(',', $all_cat);
        print "ts is @ts\n";
        my $i;
        foreach (@ts) {
            my @allfeat = split('->',$_);
            my $count =  scalar @allfeat;
            for ($i = 0; $i<$count; $i++) {
                my @temparr = @allfeat[$i..$count-1];
                print "temparr is @temparr\n";
                push @temparr, $testname;
                ToNestedHash($hash, @temparr);
            }
        }
    }
}

sub ToNestedHash {
    my $ref   = \shift;
    print "sandeep in ref ";
    dd $ref;
    my $h     = $$ref;
    print "sandeep h ";
    dd $h;
    my $value = pop;
    print "sandeep value is $value\n";
    print "sandeep array is @_\n";
    print "refrence",  ref($h), "\n";
    foreach my $i (@_) {
        print " before INDEX $i\n";
        dd $ref;
        $ref =\$$ref->{ $i };
        print "after INDEX $i\n";
        dd $ref;
    }
    $ref =\$$ref->{ _ARRAY };
    if (!isinlist(\@{$$ref},$value)) {
        push @{$$ref}, $value;
    }
    return $h;
}
# If element exists in the list
sub isinlist {
    my ($aref, $key) = ($_[0], $_[1]);

    foreach my $elem (@$aref){
        if ($elem eq $key) {
            return 1;
        }
    }
    return 0;
}

【讨论】:

  • 这一行 $ref =\$$ref->{ _ARRAY };做了魔法。谢谢@Ed。
猜你喜欢
  • 2011-04-20
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 2014-09-18
  • 2018-02-25
  • 2013-12-20
  • 2012-09-06
  • 1970-01-01
相关资源
最近更新 更多