Split string into a hash of hashes (perl)

随声附和 提交于 2021-01-01 09:24:28

问题


at the moment im a little confused..

I am looking for a way to write a string with an indefinite number of words (separated by a slash) in a recursive hash.

These "strings" are output from a text database.

Given is for example "office/1/hardware/mouse/count/200"

the next one can be longer or shorter..

This must be created from it:

{
    office {
        1{
            hardware {
                mouse {
                    count => 200
                }
            }
        }
    }
}

Any idea ?


回答1:


Work backwards. Split the string. Use the last two elements to make the inner-most hash. While more words exist, make each one the key of a new hash, with the inner hash as its value.

my $s = "office/1/hardware/mouse/count/200";

my @word = split(/\//, $s);

# Bottom level taken explicitly
my $val = pop @word;
my $key = pop @word;

my $h = { $key => $val };

while ( my $key = pop @word )
{
    $h = { $key => $h };
}



回答2:


Simple recursive function should do

use strict;
use warnings;
use Data::Dumper;

sub foo {
    my $str = shift;
    my ($key, $rest) = split m|/|, $str, 2;
    if (defined $rest) {
        return { $key => foo($rest) };
    } else {
        return $key;
    }
}
my $hash = foo("foo/bar/baz/2");
print Dumper $hash;

Gives output

$VAR1 = {
          'foo' => {
                     'bar' => {
                                'baz' => '2'
                              }
                   }
        };

But like I said in the comment: What do you intend to use this for? It is not a terribly useful structure.




回答3:


If there are many lines to be read into a single hash and the lines have a variable number of fields, you have big problems and the other two answers will clobber data by either smashing sibling keys or overwriting final values. I'm supposing this because there is no rational reason to convert a single line into a hash.

You will have to walk down the hash with each field. This will also give you the most control over the process.

our $hash = {};
our $eolmark = "\000";
while (my $line = <...>) {
  chomp $line;
  my @fields = split /\//, $line;
  my $count = @fields;
  my $h = $hash;
  my $i = 0;
  map { (++$i == $count) ?
   ($h->{$_}{$eolmark} = 1) :
   ($h = $h->{$_} ||= {});
  } @fields;
}

$h->{$_}{$eolmark} = 1 You need the special "end of line" key so that you can recognize the end of a record and still permit longer records to coexist. If you had two records foo/bar/baz foo/bar/baz/quux, the second would overwrite the final value of the first.

$h = $h->{$_} ||= {} This statement is a very handy idiom to both create and populate a cache in one step and then take a shortcut reference to it. Never do a hash lookup more than once.

HTH



来源:https://stackoverflow.com/questions/65131738/split-string-into-a-hash-of-hashes-perl

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!