
Intro
최근에 MinIO에서 한글 인코딩 문제로 고생을 했다.
이를 해결하는 과정에서 찾았던 내용을 정리할 겸 글을 쓴다.
유니코드 상에서 한글 인코딩(= 정규화) 방법에는 크게 2가지가 존재한다.
하나는 NFC이고, 하나는 NFD이다.
NFC ( Normalization Form Canonical Composition )
NFC는 모든 음절을 정준 분해 ( Canonical Decomposition ) 후 정준 결합 ( Canonical Composition ) 하는 정규화 방법이다.
쉽게 말해, 완성된 한글 한 글자를 그대로 저장하는 방법이라 생각하면 된다.
NFC를 활용하면 NFD 방식에 비해서 텍스트의 크기는 작아진다.
하지만 현대 한글과 옛 한글이 다른 방식으로 저장된다는 점은 유의해야 한다. ( References 1 참고 )
위키피디아에 있는 예시를 보자.
'위' 와 '한' 을 NFC로 정규화하려면 먼저 정준 분해 후 정준 결합을 해야 한다.
ᄋ (U+110B) + ᅱ (U+1171) → 위 (U+C704)
ᄒ (U+1112) + ᅡ (U+1161) + ᆫ (U+11AB) → 한 (U+D55C)
윈도우에서는 NFC 정규화를 기본적으로 사용한다.
리눅스의 경우 NFC와 이후에 소개할 NFD 방법을 둘다 사용한다.
하지만 리눅스에서도 주로 NFC를 사용한다.
NFD ( Normalization Form Canonical Decomposition)
NFD는 모든 음절은 정준 분해 ( Canonical Decomposition ) 한 것을 그대로 저장하는 방법이다.
한글을 다 쪼개서 저장한다고 생각하면 편하다.
NFC에 비해서는 더 많은 용량을 차지하지만, 현대 한글과 옛 한글을 동일한 방식으로 저장한다는 장점이 있다.
NFD는 macOS에서 주로 쓴다.
macOS에서 Windows로 파일을 보내면 자소가 쪼개지는 현상이 있는데, 각 OS에서 사용하는 정규화 방법이 달라서 발생하는 문제이다.
위키피디아 예시를 살펴보면, 아래처럼 정규화된다.
위 (U+C704) → ᄋ (U+110B) + ᅱ (U+1171)
한 (U+D55C) → ᄒ (U+1112) + ᅡ (U+1161) + ᆫ (U+11AB)
NFC <-> NFD 변환 방법
NFC로 정규화된 문자열과 NFD로 정규화된 문자열은 서로 유니코드 값이 다르기에, 비교하면 다른 문자열이 된다.
이것때문에 MinIO 관련 문제를 해결하는데 고생했다..
아래 Java / Python 코드를 사용하면 쉽게 변환할 수 있다.
Java
import java.text.Normalizer;
...
String str1 = "Something Here";
String strToNFC = Normalizer.normalize(str1, Normalizer.Form.NFC);
String strToNFC = Normalizer.normalize(str1, Normalizer.Form.NFD);
...
Python
import unicodedata
str1 = "Something here"
str2nfc = unicodedata.normalize('NFC', str1)
str2nfd = unicodedata.normalize('NFD', str1)
References
소프트웨어학과 현주씌의 일상을 담는 블로그
포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!