" ---- " #### / (....) / #### use strict; use warnings; my $gold_field = 'NAME'; my( @gold_aoa, @col, $pre,; $pat, $pad ); while () { chomp; if ( /^[- ]+$/ ) { # this line is a picture; turn it into a pattern $pad = ' ' x length($_); # overkill, I know. s/ -/ (-/g; s/^-/(-/g; s/- /-) /g; s/-$/-)/g; y/-/./; $pat = $_; # start looking for data. # prev contains header my @hdr = $prev =~ /^$pat/; s/\s+$// for @hdr; @col = grep { $hdr[$_] eq $gold_field } 0 .. $#hdr; next; } if ( $pat ) { $_ .= $pad; if ( my @dat = /^$pat/ ) { @dat = @dat[@col]; for my $i ( 0 .. $#dat ) { $dat[$i] =~ s/\s+$//; length($dat[$i]) and push @{ $gold_aoa[$i] }, $dat[$i]; } } else { # issue report local $, = ','; local $\ = "\n"; print map @$_, @gold_aoa; @gold_aoa = (); # stop looking for data undef $pat; } } $prev = $_; } __DATA__ Here's the original sample data: CODE NAME CODE NAME -------- ----------------------- -------- ----------------------- ABC NAME ONE RST NAME EIGHT ... DEF NAME TWO THREE WXY NAME NINE - TEN GHIJK NAME FOUR ... ZAB NAME ELEVEN LMN NAME FIVE - SIX CDE NAME TWELVE OPQ NAME SEVEN And here's another bunch of data. It all still works! CODE NAME AGE CODE NAME AGE CODE NAME AGE ---- ----- --- ---- --------- --- ---- ----------- --- ABC ONE 1 RST EIGHT 19 RS0 VEGA 39 DEF TWO 2 WXY NINE 23 WX0 SHELIAK 23 DEJ THREE 3 WXZ TEN 29 WY0 SULAFAT 29 GHI FOUR 9 ZAB ELEVEN 31 ZA0 AL ADFAR 31 LMN FIVE 10 CDE TWELVE 37 CD0 AL ATHFAR 37 LMS SIX 13 OPQ SEVEN 15