<?xml version="1.0" encoding="windows-1252"?>
<node id="35308" title="Re: varying length multi-dimensional hashes" created="2000-10-04 18:53:24" updated="2005-07-19 14:08:39">
<type id="11">
note</type>
<author id="16098">
Fastolfe</author>
<data>
<field name="doctext">
Since you're dealing with references, you can traverse your hash with a pointer-type of reference.

&lt;code&gt;
my %hash;
while (&lt;STDIN&gt;) {
   chomp;
   my $pointer = \%hash;         # start from root
   while (s/^(...)//) {          # keep eating 1st 3
      if ($_) {                  # if there's more to go,
                                 # we go deeper
         $pointer-&gt;{$1} = {} unless ref($pointer-&gt;{$1});
         $pointer = $pointer-&gt;{$1};
      } else {              
         $pointer-&gt;{$1}++;       # otherwise, set it to 1
      }
   }
}
&lt;/code&gt;

Note that the following data will mess things up slightly:

&lt;code&gt;
111222333444555
111222333

$HASH{111}-&gt;{222}-&gt;{333} == 1  # lost 444 and 555

111222333
111222333444555

$HASH{111}-&gt;{222}-&gt;{333} != 1  # now a hash reference
&lt;/code&gt;

These are unavoidable though with the criteria you've given.  This code also assumes that your string will always be of a length that is divisible by 3.  If you have two trailing characters at the end, the substitution will fail, but the test for &lt;code&gt;$_&lt;/code&gt; will have succeeded in the previous loop, giving you a dangling empty hash reference instead of 1.</field>
<field name="root_node">
35303</field>
<field name="parent_node">
35303</field>
</data>
</node>
