Combine regular expression with a dispatch table. For each regular expression you define what action should take place. In this case, the actions will add values to a hash.
Parsing is performed from left to right. As matches are found the matched text is removed from the input string. Parsing stops when no patterns match or the input string is reduced to the empty string.
use Data::Dumper;
my %patterns = (
qr/SS\s+(\d+)/
=> sub { $_->{SS} = $1 },
qr/PL\s+([=#]?)(\d+)([=#])(\d+)/
=> sub { $_->{SP} = $2; $_->{LP} = $4 },
qr/PV\s+([a-z]?\d+)(\.\d+)?/
=> sub { }, # to be written...
qr/RL\s+(\d+)([,'"])/
=> sub { $_->{RL} = $1; },
qr/SA\s+(\d+)/
=> sub { $_->{SA} = $1 },
qr/DS\s+(\d+)/
=> sub { $_->{DS} = $1 },
qr/CT\s+([#^]?)\s*(\d+)\s+(\S+)\s+(\S+)/,
=> sub { },
qr/CL\s+([#^]?)(\d+)\s+(\S+)/,
=> sub { },
);
sub MAGIC {
my $line = $_[0];
$_ = {};
$line =~ s/^\s*//;
LOOP:
while (length($line)) {
for my $k (keys %patterns) {
if ($line =~ s/^$k(?:\s+|\z)//) {
$patterns{$k}->();
next LOOP;
}
}
warn "got stuck on: $line\n";
$_->{leftover} = $line;
last;
}
$_;
}
print Dumper( MAGIC("SS 21 PL 2#3 PV 51.3 CL #110 +0 RL 126' SA 1
+06 DS 93"));
__END__
$VAR1 = {
'SA' => '106',
'DS' => '93',
'RL' => '126',
'SP' => '2',
'SS' => '21',
'LP' => '3'
};