jongseong
Version:
Hangul jongseong checker
168 lines (148 loc) • 4.3 kB
JavaScript
;
// A JongseongCode is an integer[0...27].
// - Each code represents a tail consonants.
// code | e.g.
// -------+------
// 0 | 가
// 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 | 갛
// _codeForHangul :: string -> JongseongCode
// Given a Hangul letter, computes its jongseong code.
// Assume h is a single letter Hangul string (가-힣).
// - 44032 (AC00) is the code point of 가, which is the first Hangul letter.
// - 28 = the number of the jongseongs + 1
var _codeForHangul = function _codeForHangul(h) {
return (h.charCodeAt(0) - 44032) % 28;
};
// code :: string -> JongseongCode
// Given a string of zeros, returns its jongseong code.
// e.g. _codeForZeros('00') === 1 (100 = 백)
// the number |
// of zeros |
// -----------+-------
// 1 | 십
// 2 | 백
// 3 | 천
// 4 ~ 7 | 만
// 8 ~ 11 | 억
// 12 ~ 15 | 조
// 16 ~ 19 | 경
// 20 ~ 23 | 해
var _codeForZeros = function _codeForZeros(zs) {
var n = zs.length;
if (n === 1) {
return 17;
}
if (n === 2 || n >= 8 && n <= 11) {
return 1;
}
if (n >= 3 && n <= 7) {
return 4;
}
if (n >= 12 && n <= 15 || n >= 20 && n <= 23) {
return 0;
}
if (n >= 16 && n <= 19) {
return 21;
}
throw new Error("It's too large.");
};
// _codeForDigit :: string -> JongseongCode
// Given a digit, returns its jongseong code.
// Assume d is one of: '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'
var _codeForDigit = function _codeForDigit(d) {
return [21, 8, 0, 16, 0, 0, 1, 8, 8, 0][d];
};
// _codeForEnglish :: string -> JongseongCode
// Given a two-letter English string, returns its jongseong code.
// Assume e is a two-letter English string.
var _codeForEnglish = function _codeForEnglish(e) {
return (/ck/i.test(e) ? 1 : /.n/i.test(e) ? 4 : /ne/i.test(e) ? 4 : /.l/i.test(e) ? 8 : /le/i.test(e) ? 8 : /.m/i.test(e) ? 16 : /ob/i.test(e) ? 17 : /.p/i.test(e) ? 17 : /et/i.test(e) ? 19 : /ng/i.test(e) ? 21 : /* else */0
);
};
// _codeForEnglishInitial :: string -> JongseongCode
// Given an English letter, returns its jongseong code.
// Assume e is a single-letter English string.
var _codeForEnglishInitial = function _codeForEnglishInitial(e) {
switch (e.toLowerCase()) {
case 'l':
case 'r':
return 8;
case 'm':
return 16;
case 'n':
return 4;
default:
return 0;
}
};
// code :: string -> JongseongCode
// Computes the jongseong code of a given string.
// If there isn't any recognizable letter in word, returns 0 (no jongseong).
var code = function code(word) {
if (!word) {
return 0;
}
// !!! Ignore letters inside parentheses.
var w = word.replace(/\([^)]*\)$/, '');
var last = w[w.length - 1];
if (/[가-힣]/.test(last)) {
return _codeForHangul(last);
}
if (/[1-9]0+$/.test(w)) {
var zerosMatch = /0+$/.exec(w);
return _codeForZeros(zerosMatch[0]);
}
if (/\d/.test(last)) {
return _codeForDigit(last);
}
if (/[a-z]{2}$/i.test(w)) {
return _codeForEnglish(w.slice(w.length - 2, w.length));
}
if (/(?:^|[^a-z])[a-z]$/i.test(w)) {
return _codeForEnglishInitial(last);
}
if (/(^|[^a-z])[a-z][^a-z]?$/i.test(w)) {
return _codeForEnglishInitial(w[w.length - 2]);
}
return code(w.slice(0, w.length - 1));
};
// hasJongseong :: string -> boolean
// Does the last letter of a given word have a jongseong?
var hasJongseong = function hasJongseong(w) {
return code(w) !== 0;
};
module.exports = {
_codeForHangul: _codeForHangul,
_codeForZeros: _codeForZeros,
_codeForDigit: _codeForDigit,
_codeForEnglish: _codeForEnglish,
_codeForEnglishInitial: _codeForEnglishInitial,
code: code,
hasJongseong: hasJongseong
};