my $name = qr/(?:\w+)/; my $data = qr/(?:\w+)/; my $num = qr/(?:\d+)/; my %line_is = ( header => qr/HDR($name) ($data)/, trailer => qr/TLR($num)/, additive => qr/(ADDRANGE|ADD|DELETERANGE|DELETE),/, additive_data => qr/($num),($num?),($name)/, ); $_ = qr/\G(?:$_)/ foreach values %line_is; my %data; while () { if (/$line_is{header}/gcx) { $data{header} = { company => $1, code => $2 } } elsif (/$line_is{trailer}/gcx) { $data{trailer} = { count => $1 } } elsif (/$line_is{additive}/gcx) { my $cmd = $1; warn "Bad $cmd: ", substr($_,pos) unless /$line_is{additive_data}/; push @{$data{record}}, [ $cmd, $1, $2||undef, $3 ] } else { warn "Unparsable data: ", substr($_,pos); } } use Data::Dumper 'Dumper'; print Dumper [ \%data ]; __DATA__ HDRCOMPNAME BIG000OLD111IDENTIFIER1020301WITH1010LOTS1010OF1010CRAP ADD,1234567890,,COMPNAME ADDRANGE,2468,4680,COMPNAME DELETE,987654321,,COMPNAME DELETERANGE,13579,13599,COMPNAME TLR000004