깃헙 링크
한글의 자음을 분류하려면 우선 유니코드에 대해 알아야한다.
자바스크립트는 내부적으로 문자열을 유니코드로 처리한다. 유니코드란 세상에 있는 거의 모든 문자를 담기 위헤 만들어져 있는데, OxAC00 부터 시작하여 초성(19), 중성(21), 종성(28)의 조합으로 이루어진다.
const Cho = ["ㄱ", "ㄲ", "ㄴ", "ㄷ", "ㄸ", "ㄹ", "ㅁ", "ㅂ", "ㅃ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅉ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
const Jung = ["ㅏ", "ㅐ", "ㅑ", "ㅒ", "ㅓ", "ㅔ", "ㅕ", "ㅖ", "ㅗ", "ㅘ", "ㅙ", "ㅚ", "ㅛ", "ㅜ", "ㅝ", "ㅞ", "ㅟ", "ㅠ", "ㅡ", "ㅢ", "ㅣ"];
const Jong = ["", "ㄱ", "ㄲ", "ㄳ", "ㄴ", "ㄵ", "ㄶ", "ㄷ", "ㄹ", "ㄺ", "ㄻ", "ㄼ", "ㄽ", "ㄾ", "ㄿ", "ㅀ", "ㅁ", "ㅂ", "ㅄ", "ㅅ", "ㅆ", "ㅇ", "ㅈ", "ㅊ", "ㅋ", "ㅌ", "ㅍ", "ㅎ"];
이러한 원리로 한글의 유니코드 값은 아래와 같이 계산이 된다.
한글 유니코드 = 0xAC00 + ((초성 × 21) + 중성) × 28 + 종성
이를 역으로 하여, 한 단어의 초성, 중성, 종성을 각각 이러한 방식으로 나타낼 수 있다.
const word = "한" - 0xAC00;
const 종성 = word % 28;
const 중성 = ((word - 종성) / 28) % 21;
const 초성 = (((word - 종성) / 28) - 중성) / 21;
console.log(Cho[초성], Jung[중성], Jong[종성]); // ㅎ, ㅏ, ㄴ
이제 이것을 조합하여 문자열에 해당하는 자음이 몇개 있는지 출력하는 로직을 짜보았다.
function findHangul(string) {
function isHangul(word) {
return word.charCodeAt(0) - 0xac00;
}
function validateHangul(string) {
for (let i = 0; i < string.length; i++) {
const word = string[i];
if (Cho.includes(word)) {
Language.Cho[word] += 1;
continue;
}
const unit = isHangul(word);
if (unit >= isHangul("가") && unit <= isHangul("힣")) {
const first = ((unit - (unit % 28)) / 28 - (((unit - (unit % 28)) / 28) % 21)) / 21;
const third = unit % 28;
Language.Cho[Cho[first]] += 1;
if (Jong[third]) {
const temp = Language.Jong[Jong[third]];
temp.map((part) => {
Language.Cho[part] += 1;
});
}
}
}
console.log(Language.Cho);
}
const Language = {
Cho: {
ㄱ: 0,
ㄲ: 0,
ㄴ: 0,
ㄷ: 0,
ㄸ: 0,
ㄹ: 0,
ㅁ: 0,
ㅂ: 0,
ㅃ: 0,
ㅅ: 0,
ㅆ: 0,
ㅇ: 0,
ㅈ: 0,
ㅉ: 0,
ㅊ: 0,
ㅋ: 0,
ㅌ: 0,
ㅍ: 0,
ㅎ: 0,
},
Jong: {
"": 0,
ㄱ: ["ㄱ"],
ㄲ: ["ㄲ"],
ㄳ: ["ㄱ", "ㅅ"],
ㄴ: ["ㄴ"],
ㄵ: ["ㄴ", "ㅈ"],
ㄶ: ["ㄴ", "ㅎ"],
ㄷ: ["ㄷ"],
ㄹ: ["ㄹ"],
ㄺ: ["ㄹ", "ㄱ"],
ㄻ: ["ㄹ", "ㅁ"],
ㄼ: ["ㄹ", "ㅂ"],
ㄽ: ["ㄹ", "ㅅ"],
ㄾ: ["ㄹ", "ㅌ"],
ㄿ: ["ㄹ", "ㅍ"],
ㅀ: ["ㄹ", "ㅎ"],
ㅁ: ["ㅁ"],
ㅂ: ["ㅂ"],
ㅄ: ["ㅂ", "ㅅ"],
ㅅ: ["ㅅ"],
ㅆ: ["ㅆ"],
ㅇ: ["ㅇ"],
ㅈ: ["ㅈ"],
ㅊ: ["ㅊ"],
ㅋ: ["ㅋ"],
ㅌ: ["ㅌ"],
ㅍ: ["ㅍ"],
ㅎ: ["ㅎ"],
},
};
validateHangul(string);
}
- 한글은 "가"부터 "힣"까지 문자의 유니코드로 이루어져있다.
이것을 쉽게 계산하기 위해isHangul
이라는 함수 내에서 모든 문자에 일괄적으로 0xAC00을 빼준다.- validateHangul 함수를 실행하게 되면 먼저 이 문자가 자음만으로 이루어진 문자인지 확인한다.
자음은 한글 범위의 유니코드엔 속해있지 않은 값을 가지게 되는데, 이 경우를 위해 문자 자체가 초성의 배열에 들어있는지 확인하고, 확인이 된다면 카운트한다.- 문자가 자음이 아니라면, isHangul을 통해 변형해주고, 이 문자가 "가"부터 "힣"사이의 유니코드 값인지 확인한다. 두 단어 사이의 값이어야만 한글이기 때문에 자음을 분리하는 과정을 진행하고, 아니라면 넘어간다.
- 자음은 초성, 종성에만 있기 때문에 초성, 종성에 해당하는 값을 구해주고, 초성은 바로 카운트한다.
- 하지만 종성은 겹받침 단어가 있기 때문에 종성의 경우엔 겹받침을 분리해준 배열로 이루어진 객체를 새로 만들고, 해당하는 자음을 따로 카운트해준다.
기본적으로 한글 유니코드와 분류 방법만 알면 어렵지 않게 해결되는 문제다.
하지만 한글이 아닌 다른 문자가 들어오거나 자음만 들어올 때 생길 수 있는 문제들이 있기 때문에 유효성 검사를 꼭 해줘야 한다.
한글 자음 분리는 프리온보딩 코스에서 검색기능을 만들 때 동적 검색 기능에 자음 검색기능을 추가하고 싶어 조사했던 적이 있다. 지금 기능에서 초성만 새로운 문자열로 만들어 strncmp와 같이 앞에서부터 자음이 일치하는 로직을 만들면 될 것 같다.
참고