# Assume a FIELD#...# string can't be split across lines. use strict; use warnings; use Data::Dumper; my @DATA_FIELDS = ( 'TITLE', 'DATA-A', 'DATA-B', 'DATA-C', ); # Build a regex that matches all fields and extracts a value. my $all_fields = join '|', @DATA_FIELDS; my $DATA_REGEX = qr/($all_fields)#([^#]*)#/; my @data; # store all tag data my $title_data = {}; # reference to current title's data store. while () { # the /g while ( /$DATA_REGEX/g ) { my $field = $1; my $value = $2; print "$_ -> $field, $value\n"; if( $field eq 'TITLE' ) { # store previous title data set if not empty. push @data, $title_data if %$title_data; # start new title data set $title_data = { TITLE => $value }; } else { # store field data in current title data set. push @{ $title_data->{$field} }, $value; } } } # store final title data set push @data, $title_data if %$title_data; print Dumper \@data; __DATA__ asdf asdfg=4eafvasdfadsf ashfasdf asdf qer qwer asd as dsasdi weeiwer dfhjTITLE#How are you#asdfads asdfa asdg rt wqrqw re DATA-A#item1#asdfdasfdasdasDATA-B#item2# asdfda dasfa asdfdas DATA-C#item3# aasdfDATA-A#item1a#DATA-B#item2b# asd asdf asdDATA-C#item3c# asdf asdf3132 adsf TITLE#I am fine#ads fadsfdasfdas