Fix part-number and date-code selection in ocr-extract

Part number now picks the longest hyphenated candidate instead of the
first one, matching the documented intent and preventing a short
unrelated token from being reported as the part number (which feeds
the fingerprint used for sorting).

Date code now only accepts YYWW candidates with a plausible year
(10-39) and valid calendar week (01-53), taking the last match when
several qualify; otherwise it stays null instead of guessing wrong,
since a wrong value is worse than a missing one.

Adds regression tests for both cases plus a no-plausible-candidate
case that must yield null.
This commit is contained in:
vchuser
2026-07-28 14:52:28 +02:00
parent 9098a45aec
commit 8d50334915
2 changed files with 39 additions and 5 deletions
+22 -5
View File
@@ -42,16 +42,33 @@ export function extractFields(rawText) {
matchKnown(raw, KNOWN.formFactor),
);
// Teilenummer: der laengste Kandidat, der nicht der Seriennummer entspricht.
// Teilenummer: unter den Kandidaten mit Bindestrich der laengste;
// bei gleicher Laenge der zuerst vorkommende. Echte Hersteller-
// Teilenummern sind laenger als die kurzen Codes, die sonst auf
// Etiketten stehen.
PART_NUMBER_PATTERN.lastIndex = 0;
const candidates = [...text.matchAll(PART_NUMBER_PATTERN)].map((m) => m[1]);
const withDash = candidates.filter((c) => c.includes('-'));
spec.partNumber = withDash[0] ?? null;
spec.partNumber =
withDash.length === 0
? null
: withDash.reduce((longest, current) =>
current.length > longest.length ? current : longest,
);
// Datumscode: vierstellige Zahl, die fuer sich allein steht.
// Datumscode: vierstellige Zahl der Form Jahr-Woche (JJWW), die fuer
// sich allein steht. Nur Kandidaten mit plausiblem Jahr (10-39) und
// gueltiger Kalenderwoche (01-53) kommen infrage; gibt es mehrere,
// gewinnt der zuletzt vorkommende, weil der Datumscode auf diesen
// Etiketten am Ende steht.
DATE_CODE_PATTERN.lastIndex = 0;
const dateMatch = [...text.matchAll(DATE_CODE_PATTERN)].map((m) => m[1]);
spec.dateCode = dateMatch[0] ?? null;
const dateCandidates = [...text.matchAll(DATE_CODE_PATTERN)].map((m) => m[1]);
const plausibleDates = dateCandidates.filter((raw) => {
const year = Number(raw.slice(0, 2));
const week = Number(raw.slice(2, 4));
return year >= 10 && year <= 39 && week >= 1 && week <= 53;
});
spec.dateCode = plausibleDates.length === 0 ? null : plausibleDates[plausibleDates.length - 1];
return spec;
}