forked from Yara724/api
the serial letter normalization added to the code to normalize the Heh , Ya , Kaf and etc to the correct character
This commit is contained in:
79
src/utils/plate-normalizer/plate-normalizer.service.ts
Normal file
79
src/utils/plate-normalizer/plate-normalizer.service.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { Injectable, Logger } from "@nestjs/common";
|
||||
|
||||
/**
|
||||
* Characters stripped from plate text during normalization.
|
||||
* These invisible Unicode code-points can sneak in via copy-paste
|
||||
* or OCR and break exact-match lookups against the plate letter map.
|
||||
*/
|
||||
const INVISIBLE_CHARS = [
|
||||
"\u200C", // Zero-Width Non-Joiner
|
||||
"\u200D", // Zero-Width Joiner
|
||||
"\u200E", // Left-to-Right Mark
|
||||
"\u200F", // Right-to-Left Mark
|
||||
"\uFEFF", // BOM / Zero-Width No-Break Space
|
||||
];
|
||||
|
||||
const INVISIBLE_RE = new RegExp(`[${INVISIBLE_CHARS.join("")}]`, "g");
|
||||
|
||||
/**
|
||||
* Normalize a Persian license-plate character (or short text) so that
|
||||
* visually-identical Unicode variants collapse to the canonical form
|
||||
* used in the plate letter mapping.
|
||||
*
|
||||
* Steps (in order):
|
||||
* 1. NFKC normalization — folds compatibility equivalents
|
||||
* 2. Strip invisible Unicode characters (ZWJ, ZWNJ, LTR/RTL marks, BOM)
|
||||
* 3. Convert Arabic ي (U+064A) → Persian ی (U+06CC)
|
||||
* 4. Trim leading/trailing whitespace
|
||||
*/
|
||||
export function normalizePlateText(text: string): string {
|
||||
if (!text) return text;
|
||||
|
||||
let result = String(text);
|
||||
|
||||
// 1. Unicode NFKC normalization
|
||||
result = result.normalize("NFKC");
|
||||
|
||||
// 2. Remove invisible characters
|
||||
result = result.replace(INVISIBLE_RE, "");
|
||||
|
||||
// 3. Arabic ي → Persian ی
|
||||
result = result.replace(/\u064A/g, "\u06CC");
|
||||
|
||||
// 4. Trim whitespace
|
||||
result = result.trim();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class PlateNormalizerService {
|
||||
private readonly logger = new Logger(PlateNormalizerService.name);
|
||||
|
||||
/** @see module-level {@link normalizePlateText} */
|
||||
normalizePlateText(text: string): string {
|
||||
return normalizePlateText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize a plate letter and, if it doesn't resolve in the given
|
||||
* mapping, log the raw Unicode code-points for debugging.
|
||||
*
|
||||
* @returns the numeric code from `mapping`, or `null` when the letter
|
||||
* is unknown after normalization.
|
||||
*/
|
||||
resolvePlateLetterCode(
|
||||
letter: string,
|
||||
mapping: Record<string, number>,
|
||||
): number | null {
|
||||
const normalized = this.normalizePlateText(letter);
|
||||
|
||||
const code = mapping[normalized];
|
||||
if (code !== undefined) return code;
|
||||
|
||||
this.logger.debug(
|
||||
`Unknown plate letter: ${normalized} [${Array.from(normalized).map((c) => `U+${c.charCodeAt(0).toString(16).toUpperCase().padStart(4, "0")}`).join(", ")}]`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user