Skip to content

Instantly share code, notes, and snippets.

@saml
Created March 12, 2013 19:49
Show Gist options
  • Save saml/5146359 to your computer and use it in GitHub Desktop.
Save saml/5146359 to your computer and use it in GitHub Desktop.
parse menu list to menu obj
use warnings;
use strict;
use Data::Dumper;
my $lines = [
"header1 dinner",
"header2 appetizer",
"item soup",
"item spring roll",
"header2 entree",
"item steak",
"header3 specials",
"item ice cream",
"header1 breakfast",
"item eggs"
];
# want to parse $lines to
my $output = {
title => "output",
children => [{
title => "dinner",
children => [{
title => "appetizer",
children => [{
title => "soup"
}, {
title => "spring roll"
}]
}, {
title => "entree",
children => [{
title => "steak"
}, {
title => "specials",
children => [{
title => "ice cream"
}]
}]
}]
}, {
title => "breakfast",
children => [{
title => "eggs"
}]
}]
};
sub parse_menu {
my ($lines) = @_;
my @lines = @$lines;
my $curr_level = 0; #current header level. number of open parens.
my @stack = ([]);
my $pop_n = sub {
my ($level) = @_;
while ($level > 0) {
pop @stack;
$level = $level - 1;
}
};
my $add_header = sub {
my ($value, $level) = @_;
my $header = { title => $value, children => [] };
my $children = $stack[-1];
push @$children, $header;
push @stack, $header->{'children'};
$curr_level = $level;
};
my $add_item = sub {
my ($value) = @_;
my $children = $stack[-1];
push @$children, { title => $value };
};
my $process_line = sub {
my ($line) = @_;
if (my ($level, $value) = $line =~ /^header(\d+) (.+)$/) {
$level = $level + 0;
$pop_n->($curr_level - $level + 1);
$add_header->($value, $level);
return 1;
}
if (my ($value) = $line =~ /^item (.+)$/) {
$add_item->($value);
return 1;
}
return 0;
};
while (my $line = shift(@lines)) {
last unless $process_line->($line);
}
return { title => "output",
children => shift(@stack) };
}
print Dumper(parse_menu($lines));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment