한글의 유니코드 인코딩과, javascript에서 한글 문자열을 다루는 방식

2023. 10. 19. 21:47·개발이야기

개요

이 글은 컴퓨터 세상과 javascript에서 한글이 다뤄지는 방식을 알아봅니다. 오로지 대소문자 52자와 공백문자, 문장부호만 있으면 되는 영어와는 달리 한글은 자음과 모음의 조합으로 이루어져 있습니다. 한글은 그래서, 완성형과 조합형 두 가지 형태로 저장됩니다.

'가' 부터 '힣' 까지의 11,172 자의 글자가 U+ AC00 ~ D7FF의 유니코드 공간을 할당받아 점유 중이고, 초성 'ㄱ'~'ㅎ' 와 모음(중성)과 종성이 U+ 1100 ~ 11FF의 공간을 점유중입니다. 이외에도 다른 한글관련 유니코드들이 있습니다.

조합형 글자들의 Normalization

문자의 Equivalence

이런 조합의 문제는 한글만이 겪는 것이 아닙니다. "가" 와 "ㄱ"+"ㅏ"가 동등한 것과 같은 성질을 동등성(Equivalency)이라 부르는데요. 유니코드 표준에서는 아래의 두 가지 동등성을 고민합니다.

출처: https://unicode.org/reports/tr15/

 첫번째, Canonical Equivalence 입니다. 엄밀히 똑같이 두 글자가 동등함을 의미합니다.

 두번째. Compatibility Equivalence입니다. Canoncial Equivalence에 비해 엄격하지는 않으나, 두 글자가 호환되어 동등하게 취급될 수 있음을 의미합니다. 주로 오른쪽의 기본 문자들이 비주얼적인 표현을 위해 왼쪽의 모습으로 변경된 형태임을 확인할 수 있습니다.

 Canonical에서는 화살표가 양방향이지만, Compatibility에서는 단방향입니다. 따라서 우리는 세 가지 변환을 찾아볼 수 있습니다.

- Canonical Decomposition(분해)

- Canonical Composition(조합)

- Compatibility Decomposition(분해)

Normalization Form

우리는 이 변환들을 Normalization이라 부르고, Normalization의 결과물들 중 4가지의 Normalization Form 을 유니코드 문자를 저장하는 표준으로 사용합니다.

NFD, NFC, NFKD, NFKC 이렇게 4가지의 변환이 있습니다. 더 이상 들어가면 복잡하니, 아래의 표를 참고하는 것으로 마무리하겠습니다.

출처: https://gist.github.com/Pusnow/aa865fa21f9557fa58d691a8b79f8a6d#nfkc-nfkd

맥북과 윈도우 간 파일을 주고 받을 때, 한글 파일명이 깨지는 경험을 하신적이 있으실 수 있는데요. macOS에서는 주로 NFD로, Linux/GNU 시스템과 Windows에서는 주로 NFC로 한글을 저장하기 때문입니다.


javascript 에서의 작동 예시

javascript에서 위 내용들을 확인해볼 수 있습니다. 크롬이시라면 F12에 콘솔을 열어 바로 확인해보세요.

"안녕".normalize("NFC").length
// 2
"안녕".normalize("NFD").length
// 6
"안녕".normalize("NFKC").length
// 2
"안녕".normalize("NFKD").length
// 6

[..."안녕"]
// (2) ['안', '녕']
[..."안녕".normalize("NFC")]
// (2) ['안', '녕']
[..."안녕".normalize("NFD")]
// (6) ['ᄋ', 'ᅡ', 'ᆫ', 'ᄂ', 'ᅧ', 'ᆼ']
[..."안녕".normalize("NFKC")]
// (2) ['안', '녕']
[..."안녕".normalize("NFKD")]
// (6) ['ᄋ', 'ᅡ', 'ᆫ', 'ᄂ', 'ᅧ', 'ᆼ']

이렇게 한글을 완성형과 조합형으로 분리해볼 수 있습니다. 이 때, 주의해야 할 점은 "안"의 받침 "ㄴ"과 "녕"의 초성 "ㄴ"은 다른 글자라는 것입니다.

[..."안녕".normalize("NFD")][3] === [..."안녕".normalize("NFD")][4]
//false

[..."안녕".normalize("NFD")][3].charCodeAt()
// 4354 -> U+1162
[..."안녕".normalize("NFD")][4].charCodeAt()
// 4455 -> U+1167

//유니코드는 16진법

charCodeAt() 함수를 통해 확인한 유니코드 키값이 다른것을 확인 가능합니다.

 

"쿠키".includes("ㅋ")
// false
"쿠키".includes("쿠")
// true
"쿠키".includes("쿸")
// false

기능을 개발하다보면 "ㅋ"로 "쿠키"라는 단어를 서치하고 싶을 수 있습니다. 일반적으로 "쿠키".includes("ㅋ")의 값은 False 입니다.

"쿠키".normalize("NFKD").includes("ㅋ".normalize("NFKD"))
// true
"쿠키".normalize("NFKD").includes("쿠".normalize("NFKD"))
// true
"쿠키".normalize("NFKD").includes("쿸".normalize("NFKD"))
//false

 글자들을 NFKD로 변환함으로써 우리가 원하는 기능을 구현할 수 있습니다. 아쉬운 점은 "쿸"으로 "쿠키"를 탐색할 수는 없다는 점이네요. "키"의 "ㅋ"은 초성이지만, "쿸"의 "ㅋ"는 받침이라 유니코드 키값이 다르기 때문입니다.

"쿠키".normalize("NFKD").includes("ㅋ".normalize("NFKD"))
// true
"쿠키".normalize("NFD").includes("ㅋ".normalize("NFD"))
// false

 주의해야 할점은 NFD로 변환해서는 우리가 원하는 결과를 얻지 못한다는 것인데요.

[..."쿠키".normalize("NFD")].map(i => i.charCodeAt().toString(16))
// (4) ['110f', '116e', '110f', '1175']
"ㅋ".normalize("NFD").charCodeAt().toString(16)
// '314b'
"ㅋ".normalize("NFKD").charCodeAt().toString(16)
// '110f'

NFD로 변환했을 때에는 우리가 조합형 한글을 쓸때와는 다른 영역의 유니코드 키값으로 변환되기 때문입니다.
toString(16) 은 해당 값을 16진법으로 변환해주는 함수입니다.

 

그리고 javascript에서 한글을 쓰려는 라이브러리가 하나 있어 소개하고 글을 마칩니다.

https://github.com/e-/Hangul.js/

저작자표시 비영리 동일조건 (새창열림)

'개발이야기' 카테고리의 다른 글

Node.js에서 csv 파일 다루기 및 ios-윈도우 간 한글 깨짐 문제 해결  (1) 2024.01.06
타입스크립트: ts2322 error 해결을 위한 서브타입 관련 개념 총정리  (1) 2023.11.26
HTTP의 역사: 0.9부터 3.0까지  (1) 2023.09.14
데코레이터(Decorator)  (1) 2023.09.05
Artillery와 함께, 웹 부하테스트 빠르게 익히기  (0) 2023.08.12
'개발이야기' 카테고리의 다른 글
  • Node.js에서 csv 파일 다루기 및 ios-윈도우 간 한글 깨짐 문제 해결
  • 타입스크립트: ts2322 error 해결을 위한 서브타입 관련 개념 총정리
  • HTTP의 역사: 0.9부터 3.0까지
  • 데코레이터(Decorator)
준별
준별
  • 준별
    준별개발
    준별
  • 전체
    오늘
    어제
    • 분류 전체보기 (58)
      • 개발이야기 (25)
        • 토막글 (11)
      • 일상이야기 (6)
      • 개인 공부 (23)
      • 생각과 기록 (2)
  • 블로그 메뉴

    • 홈
    • 방명록
    • Github
    • Linkedin
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    k9s
    http3.0
    nestjs
    맥북세팅
    zsh세팅
    데스크셋업
    전산기조직
    맥북터미널세팅
    artillery
    조합형
    필수툴
    바이브코딩
    persistent connection
    이산구조
    Zsh
    nodejs
    http pipelining
    터미널꾸미기
    데이터베이스
    정보보호개론
    http1.0
    powerlevel10k
    http1.1
    맥북초기세팅
    터미널세팅
    http2.0
    클램쉘
    맥북
    실전압축
    zsh-autosuggestion
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
준별
한글의 유니코드 인코딩과, javascript에서 한글 문자열을 다루는 방식
상단으로

티스토리툴바