I can't see any good reason to use Parse::RecDescent to parse fixed width records. This would seem to be using a A-bomb to crack a walnut. Surely you would be better off to unpack the data into a structure and validate from there?
In addition to the examples above you can for fun autogenerate one that does the job you want - rather ugly but it does work.
for ( reverse 1..20 ) {
$re .= sprintf "\\d{%d} {%d}|", $_, 20-$_;
}
chop $re;
$re = qr/^(?:$re)$/;
print $re, $/;
@tests = (
'01234567890123456789', # OK
'123 ', # OK
'123 ', # NOK
'123 123 ', # NOK
' ', # NOK
'123c ', # NOK
);
for(@tests){
print m/$re/ ? "'$_' #OK\n" : "'$_' #NOK\n"
}
__DATA__
(?-xism:^(?:\d{20} {0}|\d{19} {1}|\d{18} {2}|\d{17} {3}|\d{16} {4}|\d{
+15} {5}|\d{14} {6}|\d{13} {7}|\d{12} {8}|\d{11} {9}|\d{10} {10}|\d{9}
+ {11}|\d{8} {12}|\d{7} {13}|\d{6} {14}|\d{5} {15}|\d{4} {16}|\d{3} {1
+7}|\d{2} {18}|\d{1} {19})$)
'01234567890123456789' #OK
'123 ' #OK
'123 ' #NOK
'123 123 ' #NOK
' ' #NOK
'123c ' #NOK