Perl:从多维数组创建嵌套哈希时,不是HASH参考

时间:2019-01-07 07:25:07

标签: perl hash

我想通过从以->分隔的多维数组中读取值来创建嵌套哈希。

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

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

我们非常感谢您的帮助。我尝试使用转储程序模块调试和打印变量的值以及输出,并发现它是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->{$_} foreach (@_);

1 个答案:

答案 0 :(得分:2)

睡了之后,我意识到您想在哪里继续尝试下去。您关心的问题是您试图将某些哈希值既用作数组又用作哈希。有两种解决方法。检测并处理它,或者避免它。避免代码更加简洁,因此我将对其进行演示。

正如我在原始答案中提到的那样,我不确定您对'Dumper'行的想法是什么,但是Data :: Dump可能是您正在使用的内容的有用替代品,其复杂度小于Data :: Dumper模块,我当时以为您正在设法使用它。我还选择仍然为您的文件名regex替换,因为我仍然不想打扰完整的路径名。

#!/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;
}