UNPKG

text-aligner

Version:

Align text by adding spaces to each string so that all strings have the same number of English and Chinese characters.

117 lines 3.1 kB
// src/index.ts var FallbackKey = "@@fallback"; var FallbackPlaceholder = "\u2007"; var DefaultPaddingMap = { cjk: { test: (char) => isCJK(char), placeholder: "\u2001" }, [FallbackKey]: { test: FallbackKey, placeholder: FallbackPlaceholder } }; function isCJK(char) { const cjkRanges = [ // Chinese (Hanzi) ranges [19968, 40959], // CJK Unified Ideographs [13312, 19903], // CJK Unified Ideographs Extension A [131072, 173791], // CJK Unified Ideographs Extension B [173824, 177983], // CJK Unified Ideographs Extension C [177984, 178207], // CJK Unified Ideographs Extension D [178208, 183983], // CJK Unified Ideographs Extension E [63744, 64255], // CJK Compatibility Ideographs [194560, 195103], // CJK Compatibility Ideographs Supplement // Japanese ranges [12352, 12447], // Hiragana [12448, 12543], // Katakana [12784, 12799], // Katakana Phonetic Extensions // Korean ranges [44032, 55203], // Hangul Syllables [4352, 4607], // Hangul Jamo [12592, 12687] // Hangul Compatibility Jamo ]; const charCode = char.codePointAt(0); return cjkRanges.some(([start, end]) => charCode >= start && charCode <= end); } function countChars(str, rules) { const counts = { [FallbackKey]: 0 }; Object.keys(rules).forEach((key) => counts[key] = 0); for (const char of str) { let matched = false; for (const [key, rule] of Object.entries(rules)) { if (key === FallbackKey || rule.test === FallbackKey) { continue; } if (typeof rule.test === "function" ? rule.test(char) : rule.test.test(char)) { counts[key]++; matched = true; break; } } if (!matched) { counts[FallbackKey]++; } } return counts; } function findMaxCounts(counts) { const maxCounts = {}; for (const count of counts) { Object.keys(count).forEach((key) => { maxCounts[key] = Math.max(maxCounts[key] || 0, count[key]); }); } return maxCounts; } function alignText(strings, paddingMap = DefaultPaddingMap) { const normalizedPaddingMap = {}; for (const [key, value] of Object.entries(paddingMap)) { if (typeof value === "string") { if (!DefaultPaddingMap[key]) { continue; } normalizedPaddingMap[key] = { test: DefaultPaddingMap[key]?.test, placeholder: value }; continue; } normalizedPaddingMap[key] = value; } normalizedPaddingMap[FallbackKey] ??= { test: FallbackKey, placeholder: FallbackPlaceholder }; const counts = strings.map((str) => countChars(str, normalizedPaddingMap)); const maxCounts = findMaxCounts(counts); return strings.map((str, index) => { const currentCounts = counts[index]; let result = str; for (const [key, count] of Object.entries(maxCounts)) { const diff = count - currentCounts[key]; result += normalizedPaddingMap[key].placeholder.repeat(diff); } return result; }); } export { alignText }; //# sourceMappingURL=index.js.map