들어가며
사용자 목록이나 학생 목록을 만들다 보면 이름을 초성별로 필터링해야 할 때가 있습니다.
예를 들어 ㄱ을 선택하면 김서영, 강도윤처럼 초성이 ㄱ인 이름만 보여주는 방식입니다.
한글은 유니코드 규칙을 이용하면 첫 글자의 초성을 계산할 수 있습니다.
한글 초성 배열
한글 초성은 아래 순서로 구성됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const CHO_SEONG = [
"ㄱ",
"ㄲ",
"ㄴ",
"ㄷ",
"ㄸ",
"ㄹ",
"ㅁ",
"ㅂ",
"ㅃ",
"ㅅ",
"ㅆ",
"ㅇ",
"ㅈ",
"ㅉ",
"ㅊ",
"ㅋ",
"ㅌ",
"ㅍ",
"ㅎ",
];
이 배열의 인덱스가 초성 번호가 됩니다.
초성 구하기
한글 완성형 문자는 "가"부터 시작합니다.
"가"의 유니코드 값은 44032입니다.
초성 하나에는 중성 21개와 종성 28개 조합이 포함되므로, 초성 단위는 21 * 28 = 588입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const getInitial = (char) => {
const code = char.charCodeAt(0) - 44032;
if (code < 0 || code > 11171) {
return char;
}
const initialIndex = Math.floor(code / 588);
return CHO_SEONG[initialIndex];
};
console.log(getInitial("김")); // "ㄱ"
console.log(getInitial("나")); // "ㄴ"
한글 범위를 벗어난 문자는 그대로 반환하도록 처리했습니다.
이름 목록 필터링하기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const names = [
"김서영",
"이주원",
"박민수",
"최도윤",
"강도현",
"한수빈",
];
const filterByInitial = (names, initial) => {
return names.filter((name) => getInitial(name[0]) === initial);
};
console.log(filterByInitial(names, "ㄱ"));
// ["김서영", "강도현"]
각 이름의 첫 글자를 가져와 초성을 구한 뒤, 선택한 초성과 비교합니다.
React에서 사용하기
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
import { useState } from "react";
const initials = ["ㄱ", "ㄴ", "ㄷ", "ㄹ", "ㅁ", "ㅂ", "ㅅ", "ㅇ", "ㅈ", "ㅊ", "ㅎ"];
const names = ["김서영", "이주원", "박민수", "최도윤", "강도현", "한수빈"];
const NameFilter = () => {
const [selectedInitial, setSelectedInitial] = useState("ㄱ");
const filteredNames = names.filter(
(name) => getInitial(name[0]) === selectedInitial,
);
return (
<div>
<div>
{initials.map((initial) => (
<button key={initial} onClick={() => setSelectedInitial(initial)}>
{initial}
</button>
))}
</div>
<ul>
{filteredNames.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
</div>
);
};
초성 버튼을 누르면 해당 초성으로 시작하는 이름만 보여줄 수 있습니다.
마무리
한글 초성 필터링은 유니코드 규칙을 이해하면 비교적 간단하게 구현할 수 있습니다.
핵심은 첫 글자의 유니코드 값에서 "가"의 값인 44032를 빼고, 588로 나누어 초성 인덱스를 구하는 것입니다.
이 방식은 이름 목록, 주소 목록, 카테고리 필터처럼 한글 초성 검색이 필요한 UI에 활용할 수 있습니다.