Recurse over a hash without knowing any elements (except top level)

C

Christopher

I have a hash that is several levels deep.

ie:

'vars' => {
'$filers' => '10.10.10.10/32',
'$networksa' => '10.10.10.10/32',
'$networksb' => '10.50.0.0/16',
'$wintel_boxes' => '10.10.10.10/32',
},
'match' => {
'Rule' => {
'Doug' => {
'RuleSub' => {
'OUTBREAK' => {


Basically a structure similar in nature to that, basically it could go
as deep as 8 keys deep with values potentially with each key, but
usually a value as some level.

I need to iterate over this and print it out in it's structure, but
with some formatting. DataDumper does a fine job of doing it in it's
way, but I cannot customize the pretty output, plus I need to utilize
the data in other ways.

So I figure I can load the "top level" keys (say there are 3 of them),
and then recurse over each subsequent key and gather and print as I
go.

Here is what I tried:

use Config::General;

my $match_file = qq(match.conf);

my $match_conf = new Config::General(
-file => $match_file,
-AutoTrue => 1);

my %match_config = $match_conf->getall;

$depth = 0;

foreach $key (keys %match_config) {
print "\t"x$depth;
print "\n$key\n";
$depth++;
&recurse_hash($match_config{$key},$depth);
}

sub recurse_hash {

$match = shift;
$depth = shift;

print "\t"x$depth;

foreach $key2 (keys %{$match}) {
print "$key2 => $match->{$key2}\n";
($match,$depth) = &recurse_hash($match->{$key2},$depth);
}
return ($match,$depth);
}

I get some results back, but I also get some funk, plus I don't get it
all, just portions..... I have racked my brain on this, and scoured
the groups for anykind of similar problem. Most are only 3 levels
deep, and the levels are known.

Here is the results:
Top level keys are typically gonna be (vars, match, and translate):
vars
$filers =>
$networksa =>
$networksb =>
$wintel_boxes =>

match
Rule => HASH(0x17a918)
DOUG => HASH(0x17a924)
RuleSub => HASH(0x17a99c)
OUTBREAK => HASH(0x17a9a8)
mail_body => blah blahblah
mail_cc =>
page_cc =>
interval =>
GUN =>
DOS =>
PN =>
srcnet =>

translate
CT2 => HASH(0x183a44)
27-74 => HASH(0x183abc)
msg_pattern => HASH(0x183b04)
".*filename: => (.*)" = "Bad file: \1"
27-75 =>
SN =>
MSG =>
 
N

nobull

I have a hash that is several levels deep.

ie:

'vars' => {
'$filers' => '10.10.10.10/32',
'$networksa' => '10.10.10.10/32',
'$networksb' => '10.50.0.0/16',
'$wintel_boxes' => '10.10.10.10/32',
},
'match' => {
'Rule' => {
'Doug' => {
'RuleSub' => {
'OUTBREAK' => {


Basically a structure similar in nature to that, basically it could go
as deep as 8 keys deep with values potentially with each key, but
usually a value as some level.

I need to iterate over this and print it out in it's structure, but
with some formatting. DataDumper does a fine job of doing it in it's
way, but I cannot customize the pretty output, plus I need to utilize
the data in other ways.

So I figure I can load the "top level" keys (say there are 3 of them),
and then recurse over each subsequent key and gather and print as I
go.

Here is what I tried:

use Config::General;

my $match_file = qq(match.conf);

my $match_conf = new Config::General(
-file => $match_file,
-AutoTrue => 1);

my %match_config = $match_conf->getall;

$depth = 0;

You forgot to declare $depth. "use strict" would have told you about
this.
foreach $key (keys %match_config) {
print "\t"x$depth;

You forgot to declare $key. "use strict" would have told you about
this.
print "\n$key\n";
$depth++;
&recurse_hash($match_config{$key},$depth);

Why is that & in there? Do you know what it does? Do you really want
to do that?

Assuming $depth is supposed to indicate the depth within the
structure, it would be more straight-forward to do

recurse_hash($match_config{$key},1);

Anyhow it's not clear why you treat the top level specially at all.

recurse_hash(\%match_config,0);

}

sub recurse_hash {

$match = shift;

You forgot to declare $match. "use strict" would have told you about
this. By choosing not to "use strict" you instruct Perl to assume any
variable you didn't declare is a package variable and thus a global
variable with respect to the subroutine. Using global variables in
recursive subroutines is bad.
$depth = shift;

Ouch - you forgot to redeclare $depth within the subroutine. "use
strict" would not have helped you directly. But the mind-set that
goes with "use strict" that says "always declare all variables
lexically scoped in the smallest lexical scope" would have made this
error much less likely.
print "\t"x$depth;

You probably wanted that on each line - i.e inside the loop.
foreach $key2 (keys %{$match}) {

You forgot to declare $key2. "use strict" would have told you about
this.
print "$key2 => $match->{$key2}\n";
($match,$depth) = &recurse_hash($match->{$key2},$depth);

You are forgetting to check that $match->{$key2} really is a hash ref
either before you call &recurse_hash or within that inner subroutine.
"use strict" would have told you about this because you'd have got an
error when you tried to use something that wasn't a hash ref as a has
ref. Without "use strict" Perl will attempt to convert the string
into a reference by performing a symbol table lookup - this is bad.

Once again assuming $depth is supposed to indicate the depth within
the structure, you should be calling recurse_hash with $depth+1.
}
return ($match,$depth);
}

I do not understand why &recurse_hash needs to return this.

sub recurse_hash {

my $match = shift;
my $depth = shift;

return unless ref $match eq 'HASH';

foreach my $key2 (keys %{$match}) {
print "\t"x$depth, "$key2 => $match->{$key2}\n";
recurse_hash($match->{$key2},$depth+1);
}
}
I have racked my brain on this, and scoured
the groups for anykind of similar problem.

The consequences of being careles about your variable scoping and
choosing not to "use strict" are often discussed (oftem many times per
day) in the Perl newsgroups that exist. But, of course, you could not
be expected to realise that those are all "similar problems".

I would have thought recursive traversal of Perl structures is
dicussed frequently in the Perl newsgroups that exist. Usually at
least once a month. But actually, having Googled "recursive reference
group:comp.lang.perl.*" it does seem much less common than I'd expect.

Indeed the last thread I could find asking substancially the same
question as you are asking was the sixth hit I got and was way back in
August/September.

That said trawling though six hits isn't all that ownerous. When you
"scoured
the groups for anykind of similar problem" what keywords did you try?

This newsgroup does not (see FAQ). Please do not start threads here.
 
C

Christopher

I appreciate your time to go through my code. I admit that I have been
quite careless, and that I am trying to rectify that habit.

I search on "recurse hash", and probably did not use have the best use
of keywords.

Anway, again thank you for your insight.

-Chris


(e-mail address removed) (Christopher) wrote in message news:<[email protected]>...
<snipped>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top