use Regexp::Assemble; my $ra = Regexp::Assemble->new->track(1); my %dispatch = ( '^(?!START:|END:)([^*: ][^:]+):(.+)\n' => sub { my $r = shift; process_record($r); # first time will be empty record... %$r = (); # clear the record $r->{name} = $ra->mvar(1); $r->{desc} = $ra->mvar(2); }, '^START:\s*(.+)\n' => sub { $_[0]->{starttime} = $ra->mvar(1) }, '^END:\s*(.+)\n' => sub { $_[0]->{endtime} = $ra->mvar(1) }, '^(?:\* | )([^:]+):(\d+):(.+)\n' => sub { my @captures = @{$ra->mvar()}; push @{$_[0]->{items}}, [@captures[1..$#captures]], }, ); # add all the regular expressions to the R::A object $ra->add( keys %dispatch ); my $r = {}; # 'record' LINE: while (my $line = ) { # if we have a match, take the initial regular expression that matched # and use it as a key into our dispatch table and call its value. $ra->match($line) and &$dispatch{$ra->matched}->($r); } process_record($r);