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
JavaScript
// src/index.ts
var FallbackKey = "@@fallback";
var FallbackPlaceholder = "\u2007";
var DefaultPaddingMap = {
cjk: {
test: (char) => isCJK(char),
placeholder: "\u2001"
},
[]: {
test: FallbackKey,
placeholder: FallbackPlaceholder
}
};
function isCJK(char) {
const cjkRanges = [
// Chinese (Hanzi) ranges
[],
// CJK Unified Ideographs
[],
// CJK Unified Ideographs Extension A
[],
// CJK Unified Ideographs Extension B
[],
// CJK Unified Ideographs Extension C
[],
// CJK Unified Ideographs Extension D
[],
// CJK Unified Ideographs Extension E
[],
// CJK Compatibility Ideographs
[],
// CJK Compatibility Ideographs Supplement
// Japanese ranges
[],
// Hiragana
[],
// Katakana
[],
// Katakana Phonetic Extensions
// Korean ranges
[],
// Hangul Syllables
[],
// Hangul Jamo
[]
// Hangul Compatibility Jamo
];
const charCode = char.codePointAt(0);
return cjkRanges.some(([start, end]) => charCode >= start && charCode <= end);
}
function countChars(str, rules) {
const counts = {
[]: 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