階層の問題

以下の様な文字列を

foo:表示
 aa:表示
 bb:表示
 cc:表示
  dd:表示
  ee:表示
 ff:表示
bar:表示
 ff:表示
 gg:表示

↓のように変換したい問題

[
 { 'value' => 'foo',
  'data' => [
   { 'value' => 'aa', 'is_show' => 't' },
   { 'value' => 'bb', 'is_show' => 't' },
   { 'value' => 'cc',
     'data' => [
      { 'value' => 'dd', 'is_show' => 't' },
      { 'value' => 'ee', 'is_show' => 't' },
     ],
     'is_show' => 't'
   },
  ],
  'is_show' => 't',
 },
 { 'value' => 'bar',
  'data' => [
   { 'value' => 'ff', 'is_show' => 't' },
   { 'value' => 'gg', 'is_show' => 't' },
  ],
  'is_show' => 't',
 },
]

以下のようにしてみました。

#!/usr/bin/perl -w

use strict;

my $text = qq|foo:非表示
 aa:表示
 bb:非表示
 cc:表示
  dd:表示
  ee:非表示
 ff:表示
bar:表示
 ff:表示
 gg:非表示
hoge:表示
moge:表示|;

my $text2 = qq|aaa:表示
bbb:非表示
ccc:表示
ddd:表示
eee:表示|;


my @texts = split(/(?:\r\n|\r|\n)/, $text2);

# ここに入れていく
my $array = ;
# 階層
my $level_count = 0;
for(my $i=0; $i < scalar @texts; $i++) {
 # 階層が下がった
 if($level_count < ($texts[$i] =~ tr/ //)) {
  # 進んだ回数、親、配列、階層を渡す
  my $parent = $texts[$i-1];
  $level_count++; # 階層が一つ下がった
  my $child_array;
  my $is_last;
  ($i, $child_array, $level_count, $is_last) = &_array($i, $parent, \@texts, $level_count);
#  $level_count--; # 戻ってきたら一つ階層が上がる
  my $hash = {}; # 親子のペア
  my( $value, $is_show ) = ($parent =~ m/[\s+]?([^\s].+):(非表示|表示)/);
  $hash->{value} = $value;
  $hash->{is_show} = ($is_show =~ m/^表示$/ ? 't' : 'f');
  $hash->{data} = $child_array;
  # 1階層目のデータ
  push(@$array, $hash);
  # 進めた分進める
  $i = $i - 1;
  # 最後だったら終わり
  if( $is_last ) {
   last;
  }
 } else {
  # 次のデータが一つ下がるなら無視(親子の関係を作るため)
  next if($texts[$i+1] && ($texts[$i] =~ tr/ //) < ($texts[$i+1] =~ tr/ //));
  # 1階層目のデータ
  my( $value, $is_show ) = ($texts[$i] =~ m/[\s+]?([^\s].+):(非表示|表示)/);
  push(@$array, {'value' => $value, 'is_show' => ($is_show =~ m/^表示$/ ? 't' : 'f')});
 }
}

use Data::Dumper;
die Dumper $array;

sub _array {
 my $num = shift;
 my $parent = shift;
 my $texts = shift;
 my $level_count = shift;

 # ここに入れていく
 my $array = ;
 # 進めた回数
 for(my $i=$num; $i < scalar @$texts; $i++) {
  ## 階層の比較
  # 階層が一つ下がった
  if($level_count < ($texts->[$i] =~ tr/ //)) {
   my $parent = $texts->[$i-1];
   $level_count++; # 階層が一つ下がる
   my $child_array;
   my $is_last;
   ($num, $child_array, $level_count, $is_last) = &_array($i, $parent, $texts, $level_count);
#   $level_count--; # 戻ってきたら一つ階層が上がる
   my $hash = {}; # 親子のペア
   my( $value, $is_show ) = ($parent =~ m/[\s+]?([^\s].+):(非表示|表示)/);
   $hash->{value} = $value;
   $hash->{is_show} = ($is_show =~ m/^表示$/ ? 't' : 'f');
   $hash->{data} = $child_array;
   # 同じ階層のデータ
   push(@$array, $hash);
   # 進めた分進める
   $i = $num - 1;
   # 最後だったら返す
   if( $is_last ) {
    return ($#$texts, $array, $level_count, 1);
   }

  # 階層が一つ上がった
  } elsif($level_count > ($texts->[$i] =~ tr/ //)) {
   $level_count--; # 階層が一つ上がる
   return ($i, $array, $level_count);

  # 同じ階層だった
  } elsif($level_count == ($texts->[$i] =~ tr/ //)) {
   # 次のデータが一つ下がるのなら無視(親子の関係を作るため)
   next if($texts->[$i+1] && ($texts->[$i] =~ tr/ //) < ($texts->[$i+1] =~ tr/ //));
   # 次のデータも同じ階層か階層が一つ上がる場合は同じ階層のデータとして入れる
   my( $value, $is_show ) = ($texts->[$i] =~ m/[\s+]?([^\s].+):(非表示|表示)/);
   push(@$array, {'value' => $value, 'is_show' => ($is_show =~ m/^表示$/ ? 't' : 'f')});
  }
 }

 ## 最後まで行ってしまったら、そのまま帰す
 return ($#$texts, $array, $level_count, 1);
}

どなたか添削してください。

この後、逆変換もやります。