-
Notifications
You must be signed in to change notification settings - Fork 1
/
jongseong.ts
122 lines (110 loc) · 2.51 KB
/
jongseong.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
const RE_DIGIT_ZEROS = /[1-9](0+)$/;
const RE_ENG_LAST_TWO = /[a-z]{2}$/i;
const enum Jongseong {
ㄱ = 1,
ㄴ = 4,
ㄹ = 8,
ㅁ = 16,
ㅂ = 17,
ㅅ = 19,
ㅇ = 21,
}
const digitZerosMap = [
Jongseong.ㅂ, // 십
Jongseong.ㄱ, // 백
Jongseong.ㄴ, // 천
Jongseong.ㄴ, // 만
Jongseong.ㄴ, // 십만
Jongseong.ㄴ, // 백만
Jongseong.ㄴ, // 천만
Jongseong.ㄱ, // 억
Jongseong.ㄱ, // 십억
Jongseong.ㄱ, // 백억
Jongseong.ㄱ, // 천억
0, // 조
0, // 십조
0, // 백조
0, // 천조
Jongseong.ㅇ, // 경
Jongseong.ㅇ, // 십경
Jongseong.ㅇ, // 백경
Jongseong.ㅇ, // 천경
0, // 해
0, // 십해
0, // 백해
0, // 천해
];
const digitMap = [
Jongseong.ㅇ, // 영
Jongseong.ㄹ, // 일
0, // 이
Jongseong.ㅁ, // 삼
0, // 사
0, // 오
Jongseong.ㄱ, // 육
Jongseong.ㄹ, // 칠
Jongseong.ㄹ, // 팔
0, // 구
];
const engSuffix2Map: Record<string, number> = {
nd: 0,
ne: Jongseong.ㄴ,
le: Jongseong.ㄹ,
ng: Jongseong.ㅇ,
};
const engSuffixMap: Record<string, number> = {
b: Jongseong.ㅂ,
c: Jongseong.ㄱ,
d: Jongseong.ㅅ,
k: Jongseong.ㄱ,
l: Jongseong.ㄹ,
m: Jongseong.ㅁ,
n: Jongseong.ㄴ,
p: Jongseong.ㅂ,
t: Jongseong.ㅅ,
};
const engCharMap: Record<string, number> = {
l: Jongseong.ㄹ,
m: Jongseong.ㅁ,
n: Jongseong.ㄴ,
r: Jongseong.ㄹ,
};
/** @internal */
export function jongseong(word: string): number {
let w = word;
while (w.length) {
// strip paren ABC(D) => ABC
w = w.replace(/\([^)]*\)$/, "");
const last = w[w.length - 1];
const lastCharCode = last.charCodeAt(0);
if (lastCharCode >= 44032 && lastCharCode <= 55203) { // 가-힣
return (lastCharCode - 44032) % 28;
}
// digit
if (lastCharCode >= 48 && lastCharCode <= 57) { // 0-9
const zerosMatch = RE_DIGIT_ZEROS.exec(w);
if (zerosMatch) {
return digitZerosMap[zerosMatch[1].length - 1] ?? 0;
}
return digitMap[lastCharCode - 48];
}
// english
if (
lastCharCode >= 65 && lastCharCode <= 90 ||
lastCharCode >= 97 && lastCharCode <= 122
) {
const match = RE_ENG_LAST_TWO.exec(w);
if (match) {
const suffix2 = match[0].toLowerCase();
const code = engSuffix2Map[suffix2];
if (typeof code === "number") {
return code;
}
return engSuffixMap[suffix2[1]] || 0;
}
return engCharMap[last.toLowerCase()] ?? 0;
}
w = w.slice(0, w.length - 1);
}
return 0;
}