开发者

Get Perl to print full "key path" to values (Data::Dumper won't)

开发者 https://www.devze.com 2023-04-11 20:13 出处:网络
$foo{alongkeyname}{anotherlongkeyname}{yetanotherlongkeyname}{afairlyshortkeynamewellitgotlongwhileiwastypingitsoiguessnot}{bob}{something} = 1;
$foo{alongkeyname}{anotherlongkeyname}{yetanotherlongkeyname}{afairlyshortkeynamewellitgotlongwhileiwastypingitsoiguessnot}{bob}{something} = 1; 

How do I get Perl to print $foo and show me the full "path name" to get to 1? In other words, I want output that looks similar to the input above.

Data::Dumper won't do this, and the long key names wrap the output, making even the indented form less useful.

Ages ago, I wrote my own "unfold" subroutine at https://github.com/barrycarter/bcapps/blob/master/bclib.pl#L109 which outputs:

<hash HASH(0x92a33a4)> 
<key> 
alongkeyname 
</key> 
<val> 
<hash HASH(0x95103b4)> 
<key> 
anotherlongkeyname 
</key> 
<val> 
<hash HASH(0x9510464)> 
<key> 
yetanotherlongkeyname 
</key> 
<val> 
<hash HASH(0x9510434)> 
<key> 
afairlyshortkeynamewellitgotlongwhileiwastypingitsoiguessnot 
</key> 
<val> 
<hash HASH(0x95bae7c)> 
<key> 
bob 
</key> 
<val> 
<hash HASH(0x95cf8bc)> 
something: 1 
</hash HASH(0x95cf8bc)> 

</val> 
</hash HASH(0x95bae7c)> 

</val> 
</hash HASH(0x9510434)> 

</val> 
</hash HASH(0x9510464)> 

</val> 
</hash HASH(0x95103b4)> 

</val> 
</hash HASH(0x92a33a4)> 

but that's not really useful either.

Real-life project inspiring this question: pulling SYNOP/BUOY data from the XML::Simple hashified output of metaf2xml

EDIT: Thank you Ben! I tried this and it worked great on my example. Then I tried it on another hash, and got:

$VAR1 = {'remark' => [{'obsStationType' => {'stationType' => {'v' => 'AO2'},'s' => 'AO2'}},{'needMaint' => {'s' => '$'}}],'QNH' => {'inHg' => {'v' => '29.99'},'s' => 'A2999'},'visPrev' => {'distance' => {'u' => 'SM','v' => '7','rp' => '1'},'s' => '7SM'},'sfcWind' => {'wind' => {'speed' => {'u' => 'KT','v' => '3'},'dir' => {'rn' => '5','v' => '60','rp' => '4'}},'measurePeriod' => {'u' => 'MIN','v' => '2'},'s' => '06003KT'},'obsStationId' => {'id' => {'v' => 'KBTR'},'s' => 'KBTR'},'obsTime' => {'s' => '080940Z','timeAt' => {'hour' => {'v' => '09'},'minute' => {'v' => '40'},'day' => {'v' => '08'}}},'s' => 'KBTR 080940Z 06003KT 7SM SCT003 BKN200 24/23 A2999 RMK AO2 $','cloud' => [{'cloudCover' => {'v' => 'SCT'},'s' => 'SCT003','cloudBase' => {'u' => 'FT','v' => '300'}},{'cloudCover' => {'v' => 'BKN'},'s' => 'BKN200','cloudBase' => {'u' => 'FT','v' => '20000'}}],'temperature' => {'relHumid4' => {'v' => '94.15'},'dewpoint' => {'temp' => {'u' => 'C','v' => '23'}},'relHumid3' => {'v' => '94.03'},'relHumid1' => {'v' => '94.16'},'relHumid2' => {'v' => '94.17'},'air' => {'temp' => {'u' => 'C','v' => '2开发者_C百科4'}},'s' => '24/23'}};

So the question I think I want to answer is: what value of this hash will give me the "94.15" you see above? It's sort of hard to tell from the above.

(If anyone's curious, the answer is $hash{temperature}{relHumid4}{v})

MORE EDIT: Thanks, Ilmari. I tried dump_var($VAR1) w/ my VAR1 above and got...


HASH(0x9ae6764) = undef;

I also tried dump_var({$VAR1}) with the same result. I might've missed something. Could you cut and paste my VAR1 above and see if it works? I did export 'Dumper' as you indicate in your 'use' statement.


Here's a quick do-it-yourself solution:

use Data::Dumper 'Dumper';

sub dump_var {
    my ($prefix, $var) = @_;
    my @rv;
    local $Data::Dumper::Indent = 0;
    local $Data::Dumper::Terse = 1;
    if (ref $var eq 'ARRAY' and @$var) {
        for my $i (0 .. $#$var) {
            push @rv, dump_var($prefix . "->[$i]", $var->[$i]);
        }
    } elsif (ref $var eq 'HASH' and %$var) {
        foreach my $key (sort keys %$var) {
            push @rv, dump_var($prefix . '->{'.Dumper($key).'}', $var->{$key});
        }
    } elsif (ref $var eq 'SCALAR') {
        push @rv, dump_var('${' . $prefix . '}', $$var);
    } else {
        push @rv, "$prefix = " . Dumper($var) . ";\n";
    }
    return @rv;
}

and some test code:

my $foo = {
    alpha => [ 'beta', \ 'gamma' ],
    one => { two => { three => 3, four => 3.141 },
             five => { six => undef, seven => \*STDIN },
    },
    foobar => sub { print "Hello, world!\n"; },
};

print dump_var('$foo' => $foo);

which produces the output:

$foo->{'alpha'}->[0] = 'beta';
${$foo->{'alpha'}->[1]} = 'gamma';
$foo->{'foobar'} = sub { "DUMMY" };
$foo->{'one'}->{'five'}->{'seven'} = \*::STDIN;
$foo->{'one'}->{'five'}->{'six'} = undef;
$foo->{'one'}->{'two'}->{'four'} = '3.141';
$foo->{'one'}->{'two'}->{'three'} = 3;

Edit: While testing a PHP version of this code, I realized that it didn't correctly handle empty arrays and hashes. I've fixed the code so that such values are passed directly to Dumper.


Data::Dumper can print output similar to what you're looking for by setting Indent to 0.

[ben@imac ~]$ perl
use Data::Dumper;
$Data::Dumper::Indent = 0;
$foo{alongkeyname}{anotherlongkeyname}{yetanotherlongkeyname}{afairlyshortkeynamewellitgotlongwhileiwastypingitsoiguessnot}{bob}{something} = 1; 
print Dumper(\%foo);

Output:

$VAR1 = {'alongkeyname' => {'anotherlongkeyname' => {'yetanotherlongkeyname' => {'afairlyshortkeynamewellitgotlongwhileiwastypingitsoiguessnot' => {'bob' => {'something' => 1}}}}}};


For a possible solution to the problem behind your question, please see the feature announced today in the Project News for metaf2xml.

0

精彩评论

暂无评论...
验证码 换一张
取 消