Я бы предложил Data :: Diver , хотя это немного неловко, так как он хочет всегда создавать скалярные ссылки в конце, а это не то, что мы хотим.Таким образом, я немного обманываю.
Главное здесь - это то, что мы можем сэкономить усилия (в основном на обслуживании), расшифровывая все ключи одновременно и используя цикл while (внутри Data :: Diver).) вместо рекурсии, которая по своей природе более забавна для расшифровки :-) Объедините это с тем фактом, что даже если бы это была рекурсия, она была бы спрятана в хорошем, аккуратном вызове функции, этодвойной выигрыш: -)
use Data::Dumper;
use Data::Diver qw(DiveRef);
my $foo = "a:b:c:d:a";
my $bar = "a:b:c:d:z";
my $hoh = {};
sub add_item
{
my $href = shift;
my $str = shift;
my @keys = split /:/, $str;
# force an array to be autovivified if it isn't already there.
# (this is kinda cheating)
my $cheat = DiveRef($href, @keys[0..$#keys-1], 0);
my $ref = DiveRef($href, @keys[0..$#keys-1]);
# if we cheated (thus $$cheat will be undef), we need to pop that
# off.
pop @$$ref unless $$cheat;
# store this at the end.
push @{$$ref}, [ $keys[-1], $str ];
return;
}
add_item($hoh, $foo);
add_item($hoh, $bar);
print Dumper($hoh);
Надеюсь, что поможет,
ОБНОВЛЕНИЕ : После разговора с tye он предоставил более лаконичный способсделать это.Он по-прежнему использует Data :: Diver , но имеет гораздо более простое встроенное решение.(Его утверждение состоит в том, что в Perl есть ошибка: lvalue subs и push - я не знаю лучше, так что я верю его слову.)
use Data::Dumper;
use Data::Diver qw(DiveRef DiveVal);
my $foo = "a:b:c:d:a";
my $bar = "a:b:c:d:z";
my $hoh = {};
sub add_item
{
my $href = shift;
my $str = shift;
my @keys= split /:/, $str;
my $last= pop @keys;
push @{ DiveVal( $href, \( @keys ) ) ||= []}, [ $last, $str ];
return;
}
add_item($hoh, $foo);
add_item($hoh, $bar);
print Dumper($hoh);