use Data::Dumper; my $data = str2data('foo[1].bar.baz[0]', 123); print Dumper($data), "\n"; sub str2data { my($string, $value) = @_; my $tmp; my @idxs = (); for my $part (split /\./, $string) { if($part =~ /(.*?)\[(.*?)\]/) { push @idxs, $1, $2; } else { push @idxs, $part; } } while(defined(my $idx = pop @idxs)) { if($idx =~ /^\d+$/) { $tmp = []; $tmp->[$idx] = $value; $value = $tmp; } else { $tmp = {}; $tmp->{$idx} = $value; $value = $tmp; } } return $value; }