mirror of
https://github.com/itflow-org/itflow
synced 2026-09-09 08:15:12 +00:00
65 lines
2.4 KiB
TypeScript
65 lines
2.4 KiB
TypeScript
export class Numerals {
|
||
#userNumeralSet: "ascii" | "arabic-indic" | "persian" | undefined;
|
||
|
||
//* Stateless conversion of any Arabic-Indic / Persian digits to ASCII 0-9.
|
||
//* Use this when you need to normalise digits without affecting any instance's tracked numeral set (e.g. for the country-search query).
|
||
public static toAscii(str: string): string {
|
||
if (!str) {
|
||
return "";
|
||
}
|
||
// Note: yes it runs two replaces, but a replace call is really a test + manipulate, so for standard ascii input, it just runs 2x tests. Not worth splitting up and adding test guards.
|
||
return str
|
||
.replace(/[٠-٩]/g, (ch) =>
|
||
String.fromCharCode(0x30 + (ch.charCodeAt(0) - 0x0660)),
|
||
)
|
||
.replace(/[۰-۹]/g, (ch) =>
|
||
String.fromCharCode(0x30 + (ch.charCodeAt(0) - 0x06f0)),
|
||
);
|
||
}
|
||
|
||
constructor(initialValue: string) {
|
||
if (initialValue) {
|
||
this.#updateNumeralSet(initialValue);
|
||
}
|
||
}
|
||
|
||
// If any Arabic-Indic digits, then label it as that set. Same for Persian. Otherwise assume ASCII.
|
||
#updateNumeralSet(str: string): void {
|
||
if (/[٠-٩]/.test(str)) {
|
||
this.#userNumeralSet = "arabic-indic";
|
||
} else if (/[۰-۹]/.test(str)) {
|
||
this.#userNumeralSet = "persian";
|
||
} else {
|
||
this.#userNumeralSet = "ascii";
|
||
}
|
||
}
|
||
|
||
// Denormalise ASCII 0-9 to the user's numeral set. If not yet known, return as-is.
|
||
// NOTE: normalise is always called before this, so it should be impossible for the numeral set to be unknown at this point.
|
||
public denormalise(str: string): string {
|
||
if (!this.#userNumeralSet || this.#userNumeralSet === "ascii") {
|
||
return str;
|
||
}
|
||
const base = this.#userNumeralSet === "arabic-indic" ? 0x0660 : 0x06f0;
|
||
return str.replace(/[0-9]/g, (d) => String.fromCharCode(base + Number(d)));
|
||
}
|
||
|
||
// Normalize Eastern Arabic (U+0660-0669) and Persian/Extended Arabic-Indic (U+06F0-06F9) numerals to ASCII 0-9.
|
||
// Tracks the user's numeral set as a side effect so denormalise can mirror it back.
|
||
public normalise(str: string): string {
|
||
if (!str) {
|
||
return "";
|
||
}
|
||
this.#updateNumeralSet(str);
|
||
//* Fast-path ASCII (the common case) so we skip both replaces on every keystroke.
|
||
if (this.#userNumeralSet === "ascii") {
|
||
return str;
|
||
}
|
||
return Numerals.toAscii(str);
|
||
}
|
||
|
||
public isAscii(): boolean {
|
||
return !this.#userNumeralSet || this.#userNumeralSet === "ascii";
|
||
}
|
||
}
|