운영체제마다 다른 '유니코드 정규화 방식' 대응하는 방법
업무를 진행하다가 파일 다운로드 시 'Windows' 환경에서 한글이 자음과 모음으로 분리되는
자음모음 분리 현상, 자소 분리 현상
이 발생했습니다.
인코드, 디코드 방식으로는 해결이 되지 않았지만 원인을 찾기가 힘들어 삽질을 했었는데요.
이를 해결하기 위해 새롭게 알게 된 내용과 해결 방법을 적어 보도록 하겠습니다.
개요
- 유니코드 정규화 방식이란?
- Mac과 Window의 정규화 방식
- normalize()로 대응하기
1. 유니코드 정규화 방식이란?
한글을 표현하기 위해 텍스트(문자)에 대한 규칙을 정했습니다. 이것이 유니코드 정규화 방식인데 의미를 더 알아보기 앞서 기본 단어 개념을 알아보겠습니다.
Character set
: 여러 언어를 사용할 수 있는 문자 세트입니다. 대표적으로 euc-kr, ascii 가 있습니다.인코딩(Encoding)
: Character set를 컴퓨터, 시스템에서 표현할 수 있는 방법입니다. 만약 utf-8로 설정되었는데, utf-16의 문자 들어온다면 이 문자들은 깨짐 현상이 발생할 수 있습니다.유니코드(Unicode)
: 전 세계의 모든 문자를 컴퓨터에서 일관적으로 표현하고 다룰 수 있도록 설계된 산업 표준입니다.UTF-8
: Universal Coded Character Set + Transformation Format – 8-bit 의 약자입니다. 유니코드를 위한 가변 길이 인코딩 방식 중 하나입니다.
위에 적은 것과 같이 유니코드는 전 세계의 문자를 표현할 수 있습니다.
유니코드 정규화 방식
이란 유니코드가 여러 문자의 합자의 형식을 가지고 있을 때 이를 규칙에 의해 저장해 보일 수 있도록 하는 것입니다.
2. Mac과 Window의 정규화 방식
Javascript에서 지원하는 표준 정규화 방식은 NFC, NFD, NFKC, NFKD
입니다.
이 중에서 Mac은 NFD
방식, Windows는 NFC
방식을 채택했습니다.
- NFD는 모든 음절을 분해하여 자모 코드를 이용하여 저장하는 방식입니다.
한
이라는 문자가ㅎ + ㅏ + ㄴ
으로 저장하는 것입니다. - NFC는 모든 음절을 분해하고 다시 결합하여 저장하는 방식입니다.
한
이라는 문자가한
으로 저장되는 것입니다.
각각 장단점과 함께 표로 정리해 보니 차이점이 명확합니다.
NFD | NFC | |
---|---|---|
운영체제 | Mac | Windows |
한글 저장 방식 | 정준 분해 | |
글 -> ㄱㅡㄹ |
정준 분해 + 정준 결합 | |
글 -> 글 |
||
장점 | 현대 한글 === 옛 한글 | 텍스트 용량 크기가 작음 |
단점 | 텍스트 용량 크기가 큼 | 현대 한글 !== 옛 한글 |
비슷한 분해/합성 과정의 | ||
정규화 방식 | NFKD | NFKC |
여기에 또 하나 알아둘 점은, NFC 방식이 보다 보편적이어서 일반적인 html에는 NFC 방식이 적용되어 있습니다.
크롬 콘솔창에 위 내용들을 간단히 테스트 해보았습니다.
한글을 변수에 저장하면 NFC 방식으로 정규화가 진행되어 NFC/NFKC로 정규화를 했을 때는 같은 값으로 인식하고 나머지는 다른 값으로 인식합니다.
NFD 방식으로 정규화를 진행하면 ㄱㅏㅁ...
와 같은 값으로 변해야 할 것 같은 느낌이지만, 유니코드 정규화는 유니코드를 저장하는 방식에 관한 것이기 때문에 문자열의 값 자체가 분해되지는 않습니다.
하지만 두 방식의 다름으로 인해 Mac에서 작업한 파일을 Windows에서 정규화 처리 없이 받게 되면 자소분리 현상이 일어날 수 있는 것입니다.
자잘한 버그부터 보안적 이슈까지 문제가 될 수 있으니 유니코드 정규화는 중요하게 살펴야 할 요소 같습니다.
3. normalize()를 통한 대응 방법
위에서 잠깐 본 것과 같이 Javascript에는 normalize를 할 수 있는 내장 객체가 있습니다.
제가 겪은 상황을 예제로 함께 보겠습니다.
생략된 코드는 엑셀 파일을 다운받는 내용입니다. 아래 코드는 다운받을 때 파일명을 지정해준 것입니다.
여기서 파일명이 자동으로 NFD
방식으로 정규화가 이루어졌던 것 같습니다.
fileName; // 파일명 지정
위 코드에서 파일명만 NFC로 변경해 주니 Mac/Windows 모두 정상적으로 출력되었습니다.
fileName.normalize('NFC');
- 인코딩 방식에 대해 막연하게 생각했었는데 문제가 발생하고 나니 더 자세히 알아보는 기회가 된 것 같습니다.
- 유니코드 정규화에 대해 알고 있다면 다음에 비슷한 문제가 발생하더라도 더 빨리 해결할 수 있을 것 같습니다.
- 참고자료에 더 자세한 내용이 있으니 참고하시면 이해에 더 도움이 되실 것 같습니다.
참고자료
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/String/normalize#한글에_normalize_사용하기
- https://m.blog.naver.com/zagatoson/221159734459
- https://wodonggun.github.io/wodonggun.github.io/study/한글-인코딩이란.html
- http://mearie.org/journal/2008/04/brief-note-on-unicode-normalization-algorithm.ko
- https://miaow-miaow.tistory.com/28
- https://ko.wikipedia.org/wiki/유니코드
- https://ko.wikipedia.org/wiki/UTF-8