feat: toleranter Spec-Vergleich gegen OCR-Verwechslungen
This commit is contained in:
+59
@@ -53,3 +53,62 @@ export function fingerprint(spec) {
|
||||
export function isUsable(spec) {
|
||||
return typeof spec.capacityGb === 'number' && Number.isFinite(spec.capacityGb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zeichen, die OCR auf glaenzenden Etiketten regelmaessig verwechselt,
|
||||
* werden auf einen gemeinsamen Vertreter abgebildet. D bleibt bewusst
|
||||
* unangetastet, sonst kollidiert 4DRx4 mit 40Rx4.
|
||||
*/
|
||||
const CONFUSIONS = {
|
||||
O: '0', Q: '0',
|
||||
I: '1', L: '1',
|
||||
B: '8',
|
||||
S: '5',
|
||||
Z: '2',
|
||||
G: '6',
|
||||
};
|
||||
|
||||
/** Vergleichsform eines Tokens: normalisiert, ohne Trennzeichen, verwechslungsfrei. */
|
||||
export function canonical(raw) {
|
||||
const normalized = normalizeToken(raw).replace(/[^A-Z0-9]/g, '');
|
||||
let out = '';
|
||||
for (const char of normalized) {
|
||||
out += CONFUSIONS[char] ?? char;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gleicht einen gelesenen Wert gegen eine Liste bekannter Werte ab.
|
||||
* Erst exakt, dann ueber die Vergleichsform. Mehrdeutigkeit gilt als Treffer-los.
|
||||
*/
|
||||
export function matchKnown(raw, list) {
|
||||
const normalized = normalizeToken(raw);
|
||||
if (normalized === '') return null;
|
||||
|
||||
for (const candidate of list) {
|
||||
if (normalizeToken(String(candidate)) === normalized) return candidate;
|
||||
}
|
||||
|
||||
const target = canonical(normalized);
|
||||
const hits = list.filter((candidate) => canonical(String(candidate)) === target);
|
||||
return hits.length === 1 ? hits[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Zwei Specs sind vertraeglich, wenn alle beidseitig gesetzten Felder
|
||||
* in ihrer Vergleichsform uebereinstimmen. Felder, die auf einer Seite
|
||||
* fehlen, verhindern die Vertraeglichkeit nicht - die Entscheidung
|
||||
* darueber faellt in session.js.
|
||||
*/
|
||||
export function specsCompatible(a, b) {
|
||||
const fields = ['capacityGb', 'formFactor', 'rank', 'speed', 'partNumber'];
|
||||
for (const field of fields) {
|
||||
const left = a[field];
|
||||
const right = b[field];
|
||||
if (left === null || left === undefined) continue;
|
||||
if (right === null || right === undefined) continue;
|
||||
if (canonical(String(left)) !== canonical(String(right))) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user