컴퓨터 속에서 맨날 한글을 봐오고 있으면서도 막상 한글 코드에 대해서 관심 있어 하는 프로그래머는 그리 많지 않은 듯 싶다. 그리고 관심을 가진다고 해도 잘 정리된 문서가 없는 듯 싶어서 내가 아는 내용을 살짝 정리해 봅니다.
우선 한글은 조합형, 완성형, 확장 완성형, iso2022-kr, unicode 등으로 표현이 가능하며… 조합형, 완성형, 확장 완성형, iso2022-kr 등은 symbol table 과 한자 테이블 또한 가지고 있지만 여기서 관련된 내용은 거의 얘기하지 않을 겁니다.
-
조합형 (Johab)
ASC II 범위에 있는 글자는 그대로 프린트하고 한글인 경우 MSB 를 1로 세팅하고 나머지 비트를 초성(5bit) / 중성(5bit) / 종성(5bit) 을 표현하는데 사용한다. 이론 상으로 한글 11172 자를 모두 표현해낼 수 있으며 한글 입력을 처리하기가 아주 쉽다. 다만 Microsoft 에서 완성형을 선택함에 따라 잊혀진 인코딩이 되어가고 있다.
-
완성형 (EucKR)
ksx1001 에 정의되어 있으며 역시나 ASC II 범위의 글자는 그대로 프린트 한다. 한글의 경우 연속된 두 개의 바이트를 이용해서 표현하게 되며 첫번째 바이트와 두번째 바이트 모두 0xA1~0xFE 사이의 값을 가진다.
한글은 2350 자 밖에 지원하지 않지만 MS windows 에서 선택함에 따라 널리 사용되고 있다. -
확장완성형 (Unified Hangul Code)
Microsoft 에서 EucKR 에 몇 가지 글자를 더 추가한 인코딩으로 UHC, cp949 등으로도 불린다. 빈 공간에 글자를 추가해 넣었기 때문에 바이너리 값 그대로 정렬을 시도할 경우 한글의 가나다라 순서대로 정렬되지 않는 문제가 있다.
EucKR 과 마찬가지로 한글을 표현하는데는 2바이트를 사용하며 첫번째 바이트는 0x81~FE 사이 두번째 바이트는 0x41~5A, 0x61~7A, 0x81~FE 영역을 차지한다. -
iso2022-kr
EucKR 을 7bit 만 사용하며 표현하는 방식으로 RFC1557 에 정의되어 있다. Designator Sequence (0x1B 24 29 43), SO (0x0E), SI (0x0F) 등을 이용해 EucKR 을 7bit 로 변환시킨다.
Designator sequence 는 non ASC character 를 만나기 전에 아무 때나 한 번 출력하면 된다. non asc character들을 출력할 때는 ‘SO char&0x7F char&0x7F char&0x7F SI’와 같은 식으로 SO를 먼저 하나 출력하고, msb가 제거된 non sac character 값들을 모두 출력한 뒤 SI를 출력하면 된다. 이런 과정을 반복하면 EucKR 은 iso2022-KR 로 변환된다.
그 과정을 pseudo code 로 표현하자면 (위에 설명이 좀 복잡하게 보이는데 실제로 보면 간단하다.)12345678910111213141516171819print 0x1B 0x24 0x29 0x43 // Designator Sequencestats = ascwhile( char = get_next_char() ){if( stats == asc ){if( char & 0x80 ){print 0x0E // SOstats = non_asc}}else{if( !(char & 0x80) ){print 0x0F // SIstats = asc}elsechar &= 0x7F;}print char}(위의 pseudo code 에서는 Designator Sequence 를 맨 앞에 출력을 했지만 iconv 등에서는 처음으로 non asc character 를 만났을 때 출력하고 있다.)
위의 네가지 인코딩 이 그동안 많이 쓰여왔던 인코딩 들인데 국제화 시대인 지금은 오로지 한글만을 표현할 수 있는 저런 인코딩으로는 뭔가 부족하다. 그렇기 때문에 유니코드 콘소시움에서는 여러가지 언어를 함께 표현할 수 있도록 unicode 라는 글자집합(character set)을 만들어 냈으며, 유니코드를 표현하는 5가지의 encoding 을 제공하고 있다. (ucs2, ucs4, utf-7, utf-8, utf-16)
-
ucs2
2바이트 고정형 인코딩, unicode 와 4.0 버젼과 동일하다. Endian 관련해서 Big Endian 과 Little Endian 으로 표현이 가능하다.
-
ucs4
4바이트 고정형 인코딩. 길이를 제외하곤 ucs2 와 거의 동일하다.
-
utf-7
unicode 의 mail safe version. RFC1642 에 정의되어 있다. BASE64 와 비슷한 방식을 통해 unicode 를 7bit 로 표현하게 된다.
-
utf-8
가변형 인코딩으로 1바이트영역은 Asc II 와 100% 호환된다. 0x00 이 사용되지 않으므로 전통적으로 C 언어에서 사용해온 null terminated 방식을 사용하는데 문제가 없고 2바이트 이상을 사용하는 경우 특수한 규칙을 가지고 있기 때문에 validation 이 가능하다.
-
utf-16
ucs2 와 ucs4 를 적절하게 혼합해서 사용하는 방식으로 BMP (Basic Multilingual Plane) 에 들어있는 글자는 2 바이트로 표현하게 되고 그 외의 글자들은 4 바이트를 이용해서 표현하게 된다.
utf-7 과 utf-8 을 제외하고는 byte order 가 중요시 되기 때문에 BOM(Byte Order Mark) 를 문서 맨 앞에 삽입해야 한다. 그렇기 때문에 Unicode 로 작성된 텍스트 파일의 경우 BOM 을 이용해 어떤 인코딩을 사용하는 지지 알아내는게 가능하다. (utf-8 을 위한 BOM 도 존재하지만 utf-8 의 경우 Byte Order 가 정해져 있기 때문에 BOM 을 의무적으로 삽입할 필요는 없다.)
Encoding | UTF-8 | UTF-16BE | UTF-16LE | UTF-32BE | UTF-32LE |
---|---|---|---|---|---|
‘가’ | EA B0 80 | AC 00 | 00 AC | 00 00 AC 00 | 00 AC 00 00 |
Smallest code point | 0000 | 0000 | 0000 | 0000 | 0000 |
Largest code point | 10FFFF | 10FFFF | 10FFFF | 10FFFF | 10FFFF |
Code unit size | 8 bits | 16 bits | 16 bits | 32 bits | 32 bits |
Byte order | N/A | big-endian | little-endian | big-endian | little-endian |
Byte order mark | EF BB BF | FE FF | FF FE | 00 00 FE FF | FF FE 00 00 |
Minimal bytes | 1 | 2 | 2 | 4 | 4 |
Maximal bytes | 4 | 4 | 4 | 4 | 4 |
대강 ucs2, ucs4, utf-8, utf-16, utf-32 의 특징을 정리하면 위의 표와 같다. UTF-8 의 경우엔 ASC II 와 호환이 되기 때문에 영어권 언어들에서 별다른 조작 없이도 문제를 일으키지 않게 되므로 널리 쓰이고 있다. UTF-8 과 UCS2 사이의 변환은 아래와 간단한 규칙을 통해 이루어지게된다.
- 0x00~0x7F 까지는 그냥 표시한다.
- 0x80~07FF 까지는 B110xxxxx 10xxxxxx (2바이트)
- 0x0800-FFFF 까지는 B1110xxxx 10xxxxxx 10xxxxxx (3바이트)
- 이후는 UCS4 영역이고 위와 같은 방식으로 4바이트까지 확장됩니다.
보다시피 ASC II 는 그대로 표현하고 있습니다. 그리고 2바이트 이상을 사용하는 문자에서는 2진수 기준으로 앞에 붙어있는 1의 개수가 그 글자를 표시하는데 사용된 바이트 수를 나타내며, 2번째 바이트부터는 맨 앞에 10 을 붙여줌으로 이건 글자의 시작이 아니라는 걸 표시하게 됩니다. 위의 두 규칙을 지키면서 unicode 를 2진수로 바꾸어 xx 로 표시된 영역에 차례로 배치하게되면 ucs -> utf-8 변환은 끝이 납니다. 한글은 UTF-8 로 표현하게 될 경우 한 글자 당 3 바이트 씩을 차지하게 됩니다.
그리고 이 유니코드에서 한글이 차지하는 영역은 아래와 같습니다.
-
U+1100: 조합형 영역
첫가끝 코드라는 이름으로도 불리고 있으며 초성(첫), 중성(가운데), 종성(끝)이 각기 다른 영역에 배치되어 있다. 이 영역에 있는 글자들을 이용하면 한글 고어까지도 표현이 가능해진다.
한글 한 글자를 표현하는데 많은 저장공간이 필요하다는 점과, iconv 에서 첫가끝 영역 -> Euc-KR, iso2022-kr, UHC 로의 변환이 불가능한 점 등이 약간의 문제라고 생각됨. -
U+3130: 한글 자모 영역
ㄱ,ㄴ,ㄷ,ㄹ, … , ㅏ,ㅑ,ㅓ,ㅕ, … 등의 자음과 모음이 배치되어 있는 영역
-
U+AC00: 완성형 영역
가각… 같이 이미 완성되어 있는 한글 케릭터가 11172 자 배치되어 있다.
Link:
- http://mytears.org/resources/doc/Hangul_Code/
- http://www.jinsuk.pe.kr/Unicode/Unicode_intro-kr.html
- http://ko.wikipedia.org/wiki/UTF-8
- http://ko.wikipedia.org/wiki/UTF-16
- http://unicode.org
- http://www.unicode.org/charts/PDF/U1100.pdf
- http://www.unicode.org/charts/PDF/U3100.pdf
- http://www.unicode.org/charts/PDF/UAC00.pdf
Similar Posts:
- 메모리 복사 코드 최적화…
- RFC2047: Message Header Ext for Non-ASCII
- CG: dithering
- 맘에 드는 포스트 몇 개 링크…
- ICU의 charset detector…
앗 태영옹. 이런건 어디서 찾아서 공부해야 하는거에요?
저도 알려주세요!!
음….
같이 한 번 대규모 정리와 가이드를 써보실 생각은 없으십니까…!!
-_-;; 케빌 님이랑 몇몇 분 모아서 뭔가 하고픈데.. 의지가 약하군요.
조합형이 그다지 쓰이지 않는다…
다시 생각해보셨으면 하는 바램입니다.
조합형은 과정이 어땠든간에 완성형과의 싸움에서 졌고… 요 근래 조합형을 쓰는 경우는 찾아보기가 힘들지 않나 싶습니다…
예전에 대강 써놓고… 다듬는다는게… 귀차니즘으로 인해 -_-;; 이렇게 방치되고 있군요…
하튼 제가 다시 생각해본다고 조합형이 현재 그다지 쓰이고 있지 않다는 사실이 뒤집히지는 않을거 같군요… 담 번엔 익명이 아니라 이름정도는 남겨주셨음 하는군요…
http://ko.wikipedia.org/wiki/UTF-8 내용을 보충해 주십시오.
글 잘보고 갑니다:)
도움 많이 되었습니다. 고맙습니다.
UCS-4를 가리키는 MIME 이름은 UTF-32입니다.
UTF-8은 최대 6바이트가 아니라 최대 4바이트입니다. ISO 10646에서 처음에 2^16짜리 multilingual plane을 2^15개 만들어서 2^31자를 담을 수 있도록 할 계획이었지만, Unicode와 통합 과정에서 plane 수를 17개로 줄여서 담을 수 있는 글자의 총 수가 2^20 + 2^16자로 줄었습니다. (그래서, 유니코드 코드 포인트를 나타낼 때에 “20.1 비트”가 필요하다고 합니다.) 따라서, UTF-8 역시 U+10FFFF 이후의 부분을 나타낼 필요가 없기 때문에 최대 길이가 4바이트로 줄었습니다.
EUC-KR=완성형이란 등식도 약간 어폐가 있습니다. EUC-KR이나 ISO-2022-KR은 모두 ISO 2022 체계에서 나온 KS X 1001과 US-ASCII/ISO 646:KR/KS X 1003을 묶어서 표현하기 위한 인코딩 방법입니다. EUC-KR이 널리 쓰이게 된 것은 MS DOS에서 채택한 탓도 없다고 할 수 없지만, 한국 표준 당국이 ISO 2022 체계에 부합하지 않아서 Unix에서 사용하기에 문제가 많은 조합형을 꺼린 탓도 매우 큽니다. 참, 아직 조합형을 그리워하시는 분도 계실지 모르지만, 유니코드가 널리 쓰이는 지금에 와서 과거의 조합형을 쓸 이유는 눈꼽만치도 없습니다. (단, 조합형은 KS X 1001:1998 – KS C 5601-1992-에 보조 인코딩으로 들어 있습니다.)
또, UTF-16을 UCS-2와 UCS-4를 혼합해서 쓰는 방식이라고 하는 것은 오해의 소지가 너무 많습니다. BMP의 영역 가운데 1024개씩을 high surrogate(0xD800 – 0xDBFF)와 low surrogate(0xDC00 – 0xDFFF) 영역으로 따로 할당한 후 , 이 두 영역에서 각각 뽑은 16비트 코드 유니트 2개(각각이 16bit니까 둘을 더하면 32bit=4바이트겠지요)를 조합해서(이 조합을 surrogate pair라고 합니다) BMP 영역 밖의총 2^20개의 글자(즉, U+10000에서 U+10FFFF)를 표현합니다. 각 surrogate 영역이 1024=2^10이니까 둘을 조합하면 2^20자를 표현할 수 있겠지요. UCV(Unicode Code Value)에서 UTF-16으로 변환하는 식은 다음과 같습니다.
high surrogate = (ucv – 0x10000) >> 10 + 0xD800
low surrogate = (ucv – 0x10000) & 0x03ff + 0xDC00
(위 식은 좀더 optimize할 수 있습니다. 예를 들어,
http://lxr.mozilla.org/seamonkey/source/xpcom/string/public/nsCharTraits.h
를 보세요.)
예를 들어, U+10400 (Desert Alphabet의 첫번째 글자)는 UTF-32BE에서는 “00 01 04 00″이지만, UTF-16BE에서는 ‘D8 01 DC 00″입니다.
유니코드 관련 용어에 대해 좀더 명확하게 알고 싶으시면 Unicode.org의 glossary를 읽어 보시기 바랍니다.
UTF-7은 Unicode 표준에 들어 있지 않습니다. 앞으로 쓰지 않는 게 더 좋은 방법입니다. 유일하게 쓰이는 곳은 IMAP 서버와 클라이언트 사이의 폴더 이름 교환입니다. 이 경우에도 원래 UTF-7이 아니라 IMAP을 위해 변형된 UTF-7이 쓰입니다.
코멘트 하나가 모더레이트 된 상태였네요. 그나저나 cp949 가 한글음절 11172 자를 전부 지원하지 못한다는건 제가 잘못 알고 있었던 사실인가보군요. 긴 글 감사합니다.
p.s) utf-8 바이트 수 관련해선 cjkv information processing 에는 6바이트 라고 적혀 있고, 인터넷에서 찾았던 다른 자료에는 또 다르게 적혀 있어서 그냥 책에 있는 내용대로 적었던 것인데, 그 책이 출판된 이후로 바뀐 것이었나보네요. 🙂
난데없이 옛 글에 커멘트를 장황하게 달았는데, 잘 읽어 주셔서 감사합니다.
CJKV I.P가 출판된 게 2000년 초인 것으로 기억합니다. ISO/IEC에서 ISO 10646을 개정하면서 U+10FFFF 다음에 글자를 배정하지 않기로 선언한 것은 아마 더 뒤였습니다. 그렇게 해야 Unicode와 ISO 10646이 포함하는 글자나 글자 위치에서 현재에나 미래에도 완전히 동기될 수 있으니까요. 그에 따라 UTF-8을 규정한 IETF RFC도 새롭게 나왔습니다. (UTF-8은 물론 Unicode 표준에서도 규정합니다.)
x-Windows-949/UHC/통합 완성형이 현대 한글 완성 음절 전부를 모두 다 포함한다는 사실은 CJKV I.P.에도 나왔고, 그 책이 아니라도 꽤 알려진 사실인데 어째서 착각을 하셨을까요? 🙂 http://ftp.unicode.org에서 MS codepage와 Unicode의 대응표를 보아도 알 수 있고요. 그 파일을 받아다가 ‘grep -v “^#’ | grep -i SYLLABLE | wc -l’ … 11172라고 나오지요 🙂
앗… 조합형 설명에서도 nit이 있네요. nit picking을 너무 많이 한다고 미워하시지 마시길…. 🙂
KS X 1001:1998(KS C 5601-1992)에 보조 인코딩으로 들어 있는 조합형은 지원하는 한자와 심볼이 KS X 1001:1998의 ‘기본 문자 집합’에 들어 있는 것과 같습니다. 물론, 1980년대 중후반에 쓰던 여러 가지 ‘조합형의 변형’들 가운데에는 한자와 심볼의 수가 더 적은 것도 있었을 수도 있습니다.
참, ISO 2022 체계에 부합하는 EUC-KR이 그렇지 않은 조합이나 UHC보다 더 나은 점은 하나의 옥텟으로 나타내지는 글자와 2개의 옥텟으로 나타내지는 글자가 겹치는 옥텟을 쓰지 않아서 문자열 중에 어느 옥텟을 하나 주었을 때 그로부터 글자 경계를 알아내기가 비교적 쉽습니다. 조합이나 UHC는 2번째 옥텟이 하나의 옥텟으로 나타내지는 글자와 같은 값을 지니는 경우가 있어서 좀더 복잡한 과정을 거쳐야 합니다. 이런 EUC-KR의 장점은 UTF-8의 장점 중 일부와 같습니다. 물론, UTF-8은 EUC-KR이 지니지 않은 또다른 장점도 지녔습니다. (순전히 코드 배치 관점에서만 본다고 해도)
그렇군요. 🙂 아 그나저나 glibc 의 iconv (bsd 의 iconv 에도 마찬가지 문제가 있는 걸로 압니다.) 에서 첫가끝 코드를 euc-kr, iso2022-kr, uhc 로 변환하지 못하는 문제가 있는데… 저건 어쩔 수 없는 문제인가요?
iconv에 넘기기 전에 normalization을 해서 NFC로 변환한 후에 넘기면 되겠지요. ISO 10646의 관점에서 보면 U+1100 U+1161은 U+AC00과 같지 않습니다. Unicode의 관점에서는 전자가 후자의 NFD form이고 후자는 전자의 NFC form으로 같은 글자의 다른 표현이지만요. 현재 GNU iconv는 ISO 10646의 입장을 취하고 있습니다. GNU option(POSIX에는 없지만)으로 Unicode/ISO 10646 기반 인코딩이 소스 혹은 타겟 인코딩인 경우 normalization 여부나 종류를 결정할 수 있도록 해 볼 수 있겠네요. 하지만, 그것은 명령행에서나 쓸 수 있지, iconv(3)에서는 쓸 수 없겠지요. iconv(3)에서도 그게 가능하도록 하려면 인코딩 이름에 NFC, NFD 등 꼬리표를 붙여야겠네요. 꼬리표가 안 붙었으면 normalization(정규화)에 신경 쓰지 않고, 붙은 경우엔 적절한 처리를 한다. … GNU libc의 iconv 개발자인 Bruno Haible(sp?)에게 한번 얘기를 해 보겠습니다.
표준 C lib.에 있는 API만으로는 사실 국제화 프로그램을 짜기가 쉽지 않지요. (손수 많은 일을 해야 하니까요.) 그래서, ICU도 있고, glib나 Windows, Mac OS X에서 제공하는 다른 라이브러리 에 여러 API들이 더해졌고요.
nit 이란 건 처음 들어봤는데, 문서 오류 같은걸 nit 이라고 표현하나보네요. 덕분에 이것저것 많이 배우네요. 감사드립니다. 😀
트랙백을 걸 수 없어 링크로 겁니다.
덕분에 좋은 가르침 받고 갑니다.
오래된 글이군요 ^_^
잘 읽었습니다. ^_^
좋은글이에요.~잘보고갑니다~
정태영님과 photon님.
덕분에 많이 배우고 갑니다.
정리하다가 허탈해하며 즐겨찾기에 등록했습니다.
감사히 사용하겠습니다. 🙂
많이 배우고 갑니다. 감사합니다.
컴퓨터 속의 한글이라….
두벌식, 세벌식 얘기도 한 번 해 볼 만 하겠죠?
혹시 모르신다면? 세벌사랑넷 들러 보셔요.
아니면 인터넷에서 세벌식 이렇게 쳐서 검색해 보셔도 되고요…
세벌식에 대해 모르는 건 아니지만 오랫동안 익숙해져 있는 자판을 바꾸는게 쉬운 선택은 아니더라구요. 😉 두벌식, 세벌식 이야기는 물론 재밌는 이야기겠지만 저처럼 두벌식만 사용하고 있는 사람 보다는 두벌/세벌 자판을 모두 사용해본 사람이 쓰는게 훨씬 재밌는 이야기가 되지 않을까 싶네요.
좋은 글 잘 읽고 갑니다~~
공부 정말 많이 되네요 ^-^
좋은 글과 정보…
정말 감사하게 잘 읽어 보고 많이 배우고 갑니다.
감사합니다.