MO-Fuel-Tax-Back/lib/services/vin_parser.dart

31 lines
1.4 KiB
Dart

/// Extracts a 17-character VIN from OCR'd text (a photo of a door-jamb
/// sticker, dashboard plate, title, etc).
///
/// Real VINs never contain the letters I, O, or Q (they're excluded from
/// the standard specifically so they can't be confused with 1 and 0), so
/// requiring that charset both matches genuine VINs and rules out a lot of
/// incidental 17-character noise elsewhere on the sticker (barcodes text,
/// weight ratings, date codes, etc).
class VinParser {
static final _labeledVinPattern =
RegExp(r'VIN[:\s]*([A-HJ-NPR-Z0-9]{17})\b', caseSensitive: false);
// \b on both sides matters: since digits and letters are both "word"
// characters, this only matches a maximal run of exactly 17 eligible
// characters — not a 17-character slice out of an 18+ character run.
static final _bareVinPattern = RegExp(r'\b([A-HJ-NPR-Z0-9]{17})\b', caseSensitive: false);
/// Returns the VIN in uppercase, or null if nothing matching the VIN
/// charset/length was found. A labeled "VIN: ..." match is preferred
/// over a bare 17-character token, in case a busy sticker has more than
/// one candidate (e.g. also a 17-digit tire/parts barcode number).
static String? parse(String text) {
final labeled = _labeledVinPattern.firstMatch(text);
if (labeled != null) return labeled.group(1)!.toUpperCase();
final bare = _bareVinPattern.firstMatch(text);
if (bare != null) return bare.group(1)!.toUpperCase();
return null;
}
}