Хорошо, это должно сосать, а не делать то, что вы хотите. Но я потратил последний час, пытаясь получить его несколько правильно, поэтому я буду проклят. Каждое «все []» представляет собой массив из двух элементов, каждый из которых hashref: один для элементов, которые появляются после голого «ничего», а второй для элементов, появляющихся после «ничего []». Вероятно, я должен был использовать закрытие вместо того, чтобы полагаться на эту дерьмовую переменную $ is_non_bracket. Еще утром я пойду еще раз, когда я буду меньше отставать и больше стыжусь писать это.
Я думаю, что он оптимизирован для хвостового оплета (часть & SUB). Он также делает (небольшое) использование named captures.
use strict;
use warnings;
use 5.010;
use Data::Dumper;
sub construct {
my $node = shift;
return unless @_;
my $next = shift;
my $is_non_bracket = 1;
$next .= '[]' and $is_non_bracket-- if exists $node->{ $next . '[]' };
if ($next =~/(?<node>[^\[\]]+) \Q[]/x) {
if (exists $node->{ $+{node} } or not defined($node->{$next})) {
push @{ $node->{$next} }, (delete $node->{ $+{node} } // {}); #/
}
unshift @_, $node->{$next}->[$is_non_bracket] ||= {};
}
else {
$node->{$next} ||= @_ ? {} : $node->{$next};
unshift @_, $node->{$next} //= @_ ? {} : ''; #/
}
goto &construct;
}
my %hash;
while (<DATA>) {
chomp;
construct(\%hash, split m!/!);
}
say Dumper \%hash;
__DATA__
one/two/three
one/two[]/three
one/two[]/three/four
one/two[]/three/four/five[]
one/two[]/three/four/whatever
one/two/ELEVAN
one/three/sixteen
one/three[]/whygodwhy
one/three/mrtest/mruho
one/three/mrtest/mruho[]/GAHAHAH
РЕДАКТ. У Regex было дополнительное пространство после кэметы, которое заставило его сломаться; Виноват.
EDIT2: Хорошо, это утро, отредактированное в версии, которая не настолько глупа. Нет необходимости в ref, так как мы всегда передаем hashref; # /, Чтобы остановить // от borking выделения.
EDIT3: Просто заметил, что вы НЕ хотите, чтобы эти [], чтобы показать в структуре данных, так вот версия, которая не показывает им:
sub construct {
my $node = shift;
return unless @_;
my $is_bracket = (my $next = shift) =~ s/\Q[]// || 0;
if (ref $node->{$next} eq 'ARRAY' or $is_bracket) {
if (ref $node->{ $next } ne 'ARRAY') {
my $temp = delete $node->{ $next } || {};
push @{ $node->{$next} = [] }, $temp;
}
unshift @_, $node->{$next}->[$is_bracket] ||= {};
}
else {
$node->{$next} ||= @_ ? {} : $node->{$next};
unshift @_, $node->{$next} //= @_ ? {} : ''; #/
}
goto &construct;
}
EDITNaN: Вот суть того, что он: Если аргументов достаточно, мы переходим во второй раз и помещаем значение в $ next, которое быстро втягивается в подстановку, которая отнимает у нее [], если она есть: если это так, substitution возвращает 1, в противном случае s /// возвращает undef (или пустую строку, я забыл), поэтому мы используем логический - или для установки возвращаемого значения на 0; В любом случае мы устанавливаем для этого $ is_bracket.
После этого, если $ node -> {$ next} является скобкой arrayref или $ next: Если $ node -> {$ next} не был arrayref (так мы получили здесь, потому что у $ next были скобки, и это было в первый раз, когда это произошло), это либо undef, либо пустая строка, либо hashref; Мы удаляем все, что есть, и храним его в $ temp. Затем мы устанавливаем теперь пустой пул $ node -> {$ next} в arrayref и устанавливаем (push) $ temp в качестве своего первого элемента. Это означает, что, например, если «два» существовали ранее, а $ next было первоначально 'two []', затем 'two' теперь укажет на arrayref, и его старое значение будет сохранено в [0]. После того, как $ node -> {$ next} является arrayref (или если он уже был), мы деактивируем hashref в индексе, указанном $ is_backet - 0, если $ next не имеет скобок, и 1, если это было - @_. Если hashref не существует (либо потому, что он является undef, для обеих, или, возможно, для пустой строки, для 0), мы назначаем ему новый hashref с логическим или.
Если это не массив, это hashref, поэтому мы делаем то же самое, что и раньше, и смещаем полученное значение на @_.
Мы делаем все это без сдвига, потому что магия goto передает наш текущий @_ функции, которая нас заменит.
Мне кажется, что сложно построить что-то простое и непротиворечивое, если вы можете получить как 'two', так и' two [] 'на том же уровне. –
Yup, 'two' и' two [] 'всегда будут на одном уровне и могут встречаться в случайном порядке, например (' two', 'two []', 'two' и т. Д. (Так я получил хэш как я уже переименовал 'two []' в 'two' и столкнулся с другим' two')) –
Извините, я до сих пор не вижу, как строится эта структура. Не могли бы вы проследить его содержимое после обработки каждой строки, объяснив, почему там происходят изменения? –