parse static method
Parses raw text input into a structured PAN card ScanResult.
Implementation
static ScanResult parse(String rawText) {
final uppercaseText = rawText.toUpperCase();
final foundPan = _extractPanCandidate(uppercaseText);
if (foundPan != null) {
final panNumber = foundPan;
final statusChar = panNumber[3];
final surnameInitial = panNumber[4];
final holderStatus =
_holderStatusMap[statusChar] ?? 'Taxpayer Category ($statusChar)';
final Map<String, String> fields = {
'Document Type': 'Income Tax PAN Card (India)',
'PAN Number': panNumber,
'Holder Category': holderStatus,
'Taxpayer Status Code': 'Code $statusChar ($holderStatus)',
'Surname Initial': surnameInitial,
'Sequential Numbering': panNumber.substring(5, 9),
'Checksum Control Character': panNumber[9],
'PAN Syntax Status': 'Valid 10-Character Structure ✓',
};
final lines = rawText
.split(_lineSplitRegex)
.map((l) => l.trim())
.toList();
for (int i = 0; i < lines.length; i++) {
final line = lines[i];
if (_dobRegex.hasMatch(line)) {
final dobMatch = _dobMatchRegex.firstMatch(line);
if (dobMatch != null) fields['Date of Birth'] = dobMatch.group(0)!;
} else if (line.contains('GOVT OF INDIA') ||
line.contains('INCOME TAX') ||
line.contains('PERMANENT ACCOUNT')) {
continue;
} else if (i < lines.length &&
!line.contains(panNumber) &&
line.length >= 3 &&
_allCapsRegex.hasMatch(line)) {
if (!fields.containsKey('Holder Name')) {
fields['Holder Name'] = line;
} else if (!fields.containsKey("Father's Name")) {
fields["Father's Name"] = line;
}
}
}
return ScanResult(
mode: ScanMode.pan,
rawValue: rawText,
isValid: true,
confidence: 0.98,
fields: fields,
metadata: {'panNumber': panNumber, 'statusChar': statusChar},
);
}
return ScanResult(
mode: ScanMode.pan,
rawValue: rawText,
isValid: false,
confidence: 0.35,
fields: {'Document Type': 'PAN Card (Unparsed)', 'Raw Text': rawText},
);
}