sub equipSub { if ( / WDM (\w+)-(R\d+\.\d+) / ) { retrun $1, $2; } return; } sub solveSub { # similar code to locate and return strings in this part of data } sub labelSub { # similar code to locate and return strings in this part } sub munge_last_record { # do whatever you need to do with the stuff you extracted from a record } my $state = ''; my %statesubs = ( 'equip' => \&equipSub, 'solve' => \&solveSub, 'label' => \&labelSub, ); my %recdata; while () { if ( /^(Equipment:)/ ) { # start of new record if ( $state eq 'label' ) { # were we reading a previous record? munge_last_record( \%recdata ); # do something with prev. record now } %recdata = (); $state = "equip"; } elsif ( /^solved:/ ) { # time to change state die "Oops! bad state transition at $." unless $state eq 'equip'; $state = "solve"; } elsif ( /^Label:/ ) { # another state change die "Oops! bad transition at $." unless $state eq 'solve'; $state = "label"; } @tokens_found = &{$statesub{$state}}(); if ( @tokens_found ) { # what you need to do here is up to you # (it is bound to depend on the current state, so maybe # you just want to do more stuff in the statesubs) push @{$recdata{$state}}, [ @tokens_found ]; } } munge_last_record( \%recdata ); # finish off the last record