Unicode와 Encoding에 대해 몰랐던 사실들

요새 XML parser를 만들어 본다고 encoding에 대해 좀 살펴보고 있는데 제가 그동안 알아왔던 것들과 많이 차이가 나네요. 사실 그동안 십수년 프로그래밍을 하면서 I18n이나 L10n을 고려해 본적은 없었거든요. ((Internationalization (I18n), Localization (L10n) )) 대부분 UI가 없거나 UI가 있더라도 그다지 한글화같은 것을 고려하지 않았도 되었던 것이기도 했고요.

가장 오해하고 있었던 사실은 Unicode는 16bit 크기안에 다 들어갈 수 있다라고 알고 있던 것이었습니다. 그런데 살펴 보니 이것은 옛날 얘기고 현재는 plane-0에만 해당하는 범위네요. 이외에도 plane-1부터 plane-16까지 가질 수 있더군요. 물론 대부분의 현재 사용되는 문자들은 16bit안, 즉 plane-0에 들어간다고 하지만 제대로 Unicode를 fixed length string으로 지원하려고 하면 16bit char로는 불가능하다는 말이 되죠.

시험삼아 간단히 컴파일을 해보니 Windows XP에서 사용한 VC++ 2005 Express에서는 wchar_t가 16bit지만 Ubuntu의 gcc에서는 32bit네요.

원래 계획은 XML parser를 만들면서 기본적으로 wchar_t로 결과를 리턴하고 encoding이 ascii (utf-8의 subset) 인 경우 char로 결과를 리턴하도록 template class로 만들려고 했었는데 wchar_t가 16bit인 환경에서는 어째야 할지 고민이네요. 어차피 현재 사용되는 대부분의 문자들이 16bit안에 들어가므로 plane-0만 지원해도 될것 같기도 한데... 아니면 basic_string 대신 basic_string를 사용하는 방법을 사용해야 할런지... 이렇게 하려면 저장될때 byte ordering도 고려해야 하고 수많은 traits이나 function overloading을 새로 만들어 주어야 하겠죠. string literal 쓰기도 어렵겠네요. :-|

만들려는 XML parser에서는 최소 ascii, utf-8, utf-16의 encoding을 지원하려고 합니다. 이중 utf-8과 utf-16 encoding의 경우에는 wchar_t를 사용해서 결과를 리턴받도록 하고요. 어차피 utf-8, utf-16과 같이 variable length를 가지는 encoding의 열을 리턴하더라도 사용하려면 fixed length string으로 변환해야 할것 같아 미리 wchar_t의 string, 즉 wstring으로 변환해서 리턴해 준다는 목적입니다. 하지만 모든 경우 wchar_t을 사용하면 encoding이 ascii인 경우 공간의 낭비가 많아지므로 이 경우에 특별히 사용할 수 있도록 char 버전을 제공하고요.

제가 이쪽에 기초가 없다보니 아직 모르는게 많네요. 혹시 제가 잘못 알고 있거나 빠진 내용에 대해 알려주시면 고맙겠습니다. :-)

Comments

  1. 제가 생각하기에 제일 쉬운(!) 방법은.

    다른 인코딩이 들어오면 iconv같은걸 돌려서 죄다 utf-8혹은 wchat_t(16bit)로 바꿔서 처리해버리세요. ㅎㅎ utf-8이라면 내부 처리단위가 std::string이 될것이고, wchar_t라면 std::wstring이 되겠네요. libxml같은 경우도 죄다 utf-8으로 변환해서 처리하던걸로 기억한다는.. :)

    ReplyDelete
  2. iconv 라는 게 있는지도 몰랐네요. ㅎㅎ 그런데 utf-8로 encoding되었더라도 이 encoding된 char가 어차피 unicode이기 때문에 0x10FFFF 까지 저장할 수 있어야 해서 wstring이 되어야 할 것 같아요. 그리고 만약 encoding이 ascii라고 확신하더라도 ascii를 이용하여 $#10FFFF; 해버리면 결국 wstring이 필요할 것 같고... 그나마 VC++에서 wstring은 0xFFFF까지밖에 안되고... oTL

    결국 지금은 wstring-base로 pull parser를 만들어 보고 있습니다. 일단 pull parser가 완성되면 SAX, DOM은 이것으로 만들면 될 것 같아서요.

    암튼 encoding, decoding 다 구현하려고 맘먹고 있었는데 iconv 라이브러리를 사용하는게 좋겠네요. 이제 문제는 input이 왔을때 이 input이 어떤 encoding인지를 검출하는 방법을 알아내는 것이네요. 좋은 라이브러리 알려주셔서 고맙습니다. :-)

    ReplyDelete
  3. 저도 iconv를 쓸 것 같은데요. utf-8라면 한글 "자르기"와 "글자수 세는 것" 외에는 그냥 아스키 쓰듯 string 쓸 것 같습니다. utf-8을 만든 이유도 기존 프로그램의 변경없이 쓸려고 만든 거니깐요. 작업물에서 한글을 제대로 자르는 것이나 글자수를 정확히 세는 것이 중요한가요?

    ReplyDelete
  4. 꼭 제대로 자르거나 글자수 세는게 문제가 아니더라도 utf-8 string가지고는 출력을 할수 없지 않나요? 결국 unicode를 사용해서 출력하려고 해도 decoding을 해야 할것 같아요. 물론 전체 utf-8 문서가 ascii만 가지고 있다면 모르겠지만요.
    아마 기존 프로그램의 변경 없이라는 얘기는 기존 ascii 문서의 변경없이라는 얘기가 아닐까요?

    게다가 전부 ascii라도 &12345; 같은 unicode 문자를 그냥 저렇게 사용하지는 않을 것 같고 하나의 문자로 나타내야 하는데 이런 것까지 고려한다면 결국은 ascii 포함해서 모든 encoding이 fixed length로 변환되려면 최소 21bit(전체 unicode)가 필요하지 않을까 생각중입니다. 물론 16bit만 있어도 현재 사용되는 모든 문자는 가능하다고 하니 이정도만 있어도 될것 같고요.

    2000 이전의 Windows NT 버전들을 이 16bit범위의 unicode만 지원했다고 하네요. 현재는 utf-16 지원.

    그리고 iconv외에 icu라는 ibm에서 시작한 라이브러리가 있군요. 좀 덩치가 큰것 같긴 하지만 살펴보고 있습니다. :-)

    ReplyDelete
  5. 윈도우즈는 utf-8을 표준 입출력으로 뿌려서 인식이 안되나요? 저는 리눅스나 BSD에서 할때는 utf-8 로케일에서 그대로 utf-8 string을 뿌려버립니다. 웹 프로그래밍할때도 utf-8 로케일이기 때문에 그냥 뿌립니다.

    만약에 윈도우즈가 표준입출력에 대한 로케일을 utf-8로 할 수 없다면 디코딩할 수 밖에 없겠네요.

    ReplyDelete
  6. 네. utf-8 인코딩을 지원하는 환경이라면 그냥 사용하셔도 되겠죠. 그리고 웹 프로그래밍에서도 그냥 utf-8을 사용하면 브라우저가 이를 지원할테니 문제 없을거고요.
    하지만 윈도우즈는 native encoding이 utf-16이니 utf-8을 바로 사용할수는 없을 것 같네요.

    현재로써는 어느 encoding이든지 wchar_t를 사용하는 wstring을 사용해서 구현해 볼 생각입니다. :-)

    ReplyDelete
  7. 결론은 iconv를 써서 후다닥 특정 인코딩으로 강제한 뒤에 파싱 ㄱㄱ 이군요.

    :)

    ReplyDelete
  8. 네. 지금 만들고 있는 parser는 일단 wchar_t로 변환 후 파싱합니다. fixed width character가 traversing 하기에 편해서요. ;-)

    ReplyDelete

Post a Comment

Popular Posts