요즘은 유니코드 문서를 사용하는 프로그램을 하나 짜고 있습니다. c 라이브러리만 가지고 유니코드를 사용하기 위해 공부하다 보니 다른 인코딩과 관련된 자료들도 보게 되는데, 완성형과 조합형만 알면 해결되던 도스 시절에 비해 정말 놀라울 정도로 복잡하고 지저분하군요. 한글은 참 효율적이고 심플하면서도 범용성이 높은 문자지만, 공학적인 견지에서는 디자인의 비일관성때문에 약간 골치아픈 문자라고 생각합니다. 아니면 다른 무식한 문자들과 함께 사용하려니 어려운 걸까요 -_-

1. KS 완성형(KSC5601, ISO2022-KR, euc-kr)

한글 코드와 관련된 그 모든 저주의 시작. 누가 어쩌자고 이런 절름발이를 국가 표준으로 정했는지 때려주고 싶을 정도죠. 아마 국제 표준인 ISO-2022에 맞추어 황급히 제작했을 것으로 추측합니다.
KSC5601은 KS 표준번호, ISO2022는 ISO 표준번호고, euc-kr은 유닉스에서 붙인 인코딩 scheme 이름입니다. KSC5601은 역슬래시 기호 대신 원화 기호를 쓴다는 점에서 아주 약간 다릅니다. 윈도우 환경에서는 더 쓰이지 않지만, 인터넷 환경에서의 파일시스템은 주로 POSIX 호환 OS들이 지배하는 관계로 여전히 네트워크에서 많이 사용되는 인코딩입니다.
0x00-0x9F 영역은 아스키 코드와 ISO 표준 제어문자가 사용하고 있는 관계로, 완성형 코드는 첫번째와 두번째 octet에서 모두 0xA1-0xFE까지를 사용합니다. 그래서 94*94 = 8836개의 코드 영역에 2350자의 한글, 4888자의 한자, 1128자의 특수문자, 470자의 기타 문자가 그야말로 '순서대로' 들어가 박혀 있습니다. 정렬할 때 문제가 없고 아스키 영역과 충돌하지 않는다는 점을 제하면 자소 추출도 테이블 없이는 불가능하고 안 써지는 글자도 많은 무책임한 인코딩. 16비트 인코딩을 고집해야 했다면 차라리 특수문자가 없었으면 좀 나았을지도 모르는데 말이죠.
ISO-2022-KR은 한글 메일 인코딩에서 사용되는 인코딩 방식입니다. 같은 국제 표준이라도 유니코드와 달리 7비트 기반인 ISO-2022는 escape 문자를 이용해 영역마다 인코딩 문자셋을 지정해주는 방식이므로, 각 octet의 첫 비트가 1이 아니라 0이라는 점을 제외하면 KS5601과 동일합니다.

2. KSSM 조합형

완성형이 나오기 전에 삼보에서 내놓아 널리 사용되었지만 표준에 채택되지는 못하다가 나중에 컴퓨터업계의 반발에 못 이겨 뒤늦게 표준으로 채택된 인코딩방식. 한글 인코딩 문제를 공학적으로 깔끔하게 해결하고 있는 나쁘지 않은 방식이지만, ISO-2022가 나오기 전에 나온 방식이라 국제 표준으로 채택되는 데 무리가 있었고, 덕분에 금방 사용자들에게서 잊혀지고 말았습니다.
16비트 중 처음 1비트를 제하고, 나머지 15비트를 초성/중성/종성에 각각 5비트씩 할당하여 인코딩하고 있습니다. 문제는 이 중성 5비트중 3번째 비트가 2번째 octet의 첫 비트가 되는데, 이 3번째 비트에서 0을 사용하는 모음들이 있어 뒤쪽 octet이 ascii code와 어쩔 수 없이 겹치게 된다는 점이죠. 그래서 영어 한글자로 조합형 문서 내에서 검색을 수행하는데 엉뚱하게 한글 글자가 검색에 걸리는 문제가 발생합니다. 완성형은 양쪽 octet에서 모두 코드 영역을 0xA1-0xFE로 제한하여 글자수가 치명적으로 줄어들었지만, 아스키 영역과 충돌하지 않는 장점이 있었고, 덕분에 ISO2022에 채택될 수 있었습니다. 덕분에 DOS나 유닉스에서는 완성형을 운영체제 표준으로 채택하게 되었고, 조합형은 완전히 기억에서 사라진 것이죠.
물론 조합형이 사용되지 않게 된 것에는 이것 말고도 여러가지 정치적인 이유도 있습니다만, 기술적인 이유가 없었던 것도 아니라는 뜻입니다. 그래도 도스 시절엔 뜻있는 많은 사람들의 지지를 받았던 인코딩입니다.

3. 확장완성형(codepage 949 혹은 UHC)

codepage 949는 MS에서 내부적으로 사용하는 한국어 로케일의 코드번호입니다. 윈도우 95와 98에서 사용되었던 것으로 알고 있으며, 이후 비 NT 커널이 완전히 퇴출당하면서 사라졌습니다. 완성형이 자소 추출 코드를 짜기가 불편한 정도였다면, 확장완성형은 프로그래머 입장에서는 완전히 악몽같은 인코딩입니다. 음절 개수를 추가하느라 0xA1-0xFE 바깥의 새로운 코드영역([0x81-0xA1][0x41-0xFE], [0xA1-0xC6][0x41-0xA0])을 사용하기 때문에 프로그램을 별 생각없이 짜면 ascii code가 검색에 걸리는 경우가 생기는데다가, euc-kr에서 이미 정의해둔 영역은 건드리지 않고 새로운 영역에 군데군데 빠진 글자들을 추가하느라 이 부분을 적절히 변환해주지 않으면 정렬조차 제대로 되지 않습니다.
물론 윈도우 api가 이런 부분을 어느정도 보완해주기는 하지만, 도저히 일반적인 목적으로는 써먹을 수 없는 인코딩이죠. 여전히 FAT32 파일시스템에서는 이걸 사용하고 있는 것으로 알고 있습니다. 지나간 악몽으로 치부하기엔 아직 무리가 있는 것 같군요.

4. 유니코드 인코딩

ㄱ. 유니코드 소개

이제 유니코드가 등장하면서 한글 인코딩과 관련된 문제들은 모두 해결되었다! 고 외칠 수 있으면 얼마나 좋겠습니까마는, 문제는 간단치 않습니다. 여기서는 UCS-2와 UTF-8만 소개하겠지만, 같은 유니코드라도 버전이 1.0에서 4.1까지 벌써 다종다양하고, 같은 버전에서도 인코딩 방식이 서로 달라서 통일된 인코딩 문제는 아직도 험난하기만 합니다.
유니코드에 왜 이런 문제가 존재하는지 알기 위해서는 유니코드에 대해 정확히 이해해야 합니다. 일단 유니코드는 만국 공통으로 사용할 수 있는 하나의 표준화된 코드를 제정하기 위한 두 단체, 즉 기업들의 주도로 이루어진 유니코드 컨소시엄과 ISO 표준안의 하나였던 ISO/IEC 10646 사이의 타협의 결과입니다. 세계에 존재하는 모든 문자들에 각각 서로 다른 번호를 붙여 사용함으로서 같은 문서 내에 여러가지 문자들이 공존할 수 있게 하려는, 꽤나 기특한 프로젝트지요.
그러나, 이 많은 문자들이 기존의 8bit 인코딩 안에 들어갈 리는 없고, 기존의 8bit 기반 문서와 호환은 하고 해야 하니 여기서부터가 딜레마의 시작이 됩니다. 그래서 유니코드는 character set과 encoding의 두 가지로 문제를 분리했습니다. character set은 전 세계 문자들에게 서로 다른 번호를 부여해 그것을 table로 만드는 것이고, encoding은 그렇게 부여된 번호를 어떻게 기록하는가의 문제입니다. UCS-2와 UTF-8은 바로 encoding 방식을 가리킵니다. 다행인 점은 이들 encoding scheme은 character set을 어떻게 코드로 변환할 것인가 하는 알고리즘의 문제라서, 테이블 없이 간단한 함수를 통해 인코딩 방식을 서로 전환하는 것이 가능합니다. 이정도만 해도 국제표준을 제정한 보람이 있다 하겠지요.

ㄴ. 유니코드의 한글 영역

유니코드 character set에서 한글이 차지하는 영역은 세 개로 나눌 수 있습니다. 첫번째는 0x1100-0x11F9 까지의 한글 자모 영역. 한글에서 사용되는 자모들을 초성 자음/중성 모음/종성 자음으로 각각 나누어 한글자씩 대응시킵니다. 두번째는 0x3130-0x318E까지의 한글 호환 자모 영역. 이 부분은 초/중/종성을 구분하지 않고 그냥 사용되는 모든 자모들이 한데 묶여 들어 있습니다. 세번째는 0xAC00-0xD7A3까지의 한글 영역. 이 부분에는 현대 한글 자모로 표현 가능한 모든 한글 문자들이 들어 있습니다. 조합형 한글의 장점도 함께 갖고 있어, 두세줄의 코드를 통해 자모를 추출하는 것도 가능합니다. 그 외 한자들은 다른 영역에 포함되어 있습니다.

ㄷ. UCS-2

UCS-2는 이렇게 지정된 character set을 단순하게 16bit로 인코딩합니다. NT계열 OS에서 사용하고 있는 방식이지요. 심플하지만 이전까지의 8bit 인코딩 방식을 사용하는 프로그램과 어쩔 수 없이 충돌을 일으켜야 하는 문제점을 지니고 있습니다. 이 인코딩 방식은 유니코드 3.x까지만 유효한데, 유니코드 4.x 부터는 문자 개수들이 너무 많아 도저히 65,536개의 번호로 다 나타낼 수 없었기 때문입니다. 사실 이 문제는 예전부터 예견되어 왔던 문제입니다. 알려진 한자의 개수만 10만개가 넘는 걸로 알려져 있으니 말이죠. 때문에 유니코드 3.1부터는 20bit의 코드 영역을 가지고 백만개의 글자를 표현할 수 있도록 character set의 체계를 변경하였습니다. 그에 맞추어 UCS-2 대신 32비트 인코딩 방식인 UCS-4도 함께 소개되었습니다만, 아직 이 방식을 사용하는 프로그램은 없는 것으로 알고 있습니다.

ㄹ. UTF-8

UTF-8은 이전까지의 8bit 방식 프로그램들과의 호환성을 목표로 만들어진 인코딩 방식입니다. 물론 20bit에 매핑된 코드들이 8bit 256개의 코드 안에 다 들어가는 것은 물론 아니므로, UTF-8 방식은 가변 길이 인코딩 방식입니다. UTF-8에서는 U+0000 ~ U+007F까지의 128자는 1바이트로 표현되는데 이는 ASCII와 동일합니다. 이로서 호환성을 간편하게 유지할 수 있죠. 또 U+0080 ~ U+07FF까지는 두 바이트, U+0800 ~ U+FFFF까지는 세 바이트로 표현됩니다. 그 이후의 코드들도 각각 인코딩 영역을 갖고 있어 최대 여섯 바이트 내에서 20bit로 인코딩된 문자셋 상의 모든 문자들을 표현할 수 있게 됩니다.
UTF-8은 가변길이라는 약점이 존재하지만, 그 점을 제하면 용량 절약에도 상당히 도움이 되고 아스키 코드 기반인 유닉스 파일시스템과도 호환이 비교적 간편한 좋은 인코딩 방식입니다. 한글 인코딩 문제를 걱정하는 많은 분들이 네트워크상의 한글 문서들을 차차 UTF-8으로 변경해야 한다고 생각하고 계시는 모양이지만, 윈도우 파일시스템과 호환이 되지 않아 좀처럼 여의치 않은 것 같습니다.

여기까지 요 며칠간 공부한 내용을 간단히 정리해 보았습니다. 이중에 뭐가 한글을 위해 가장 나은 방법인지는 저도 잘 모르겠어요. 유니코드가 제일 좋은 대안인 것은 확실하지만, 인코딩에서 갈등이 존재해서야 이전보다 상황을 복잡하게 만들 뿐인 것 같기도 하고... 윈도우가 과감히 UTF-8을 채택하거나 유닉스 시스템들이 UTF-16으로 전환해 준다면 제일 좋을 것 같기도 한데 말이죠.