본문 바로가기

카테고리 없음

CP949를 UCS4로 안전하게 변환하는 C++ 기법

  1. #include <iostream>
  2. #include <stdio.h>
  3. #include <locale>
  4.  
  5. using namespace std;
  6. typedef __enc_traits enc_type;
  7. typedef codecvt<wchar_t, char, enc_type> unicode_codecvt;
  8. typedef codecvt_base::result result;
  9. typedef wchar_t int_type;
  10. typedef char ext_type;
  11. typedef __gnu_cxx::char_traits<int_type> int_traits;
  12.  
  13. int main(void)
  14. {
  15.     locale loc(locale::classic(), new unicode_codecvt);
  16.     if (!has_facet<unicode_codecvt>(loc)) {
  17.         cerr << "don’t have facet" << endl;
  18.         return -1;
  19.     }
  20.     const unicode_codecvt* cvt = &use_facet<unicode_codecvt>(loc);
  21.     unicode_codecvt::state_type state01("UCS4", "UHC");
  22.     if (state01._M_good() == false) {
  23.         cerr << "can’t make state" << endl;
  24.         return -1;
  25.     }
  26.     state01._M_init();
  27.  
  28.     const ext_type* e_lit = "쒝 슌 꽌";
  29.     const ext_type* e_lit2 = "시냇물 처졸 냇";
  30.     const ext_type* efrom_next;
  31.     int_type* i_arr = new int_type[1024];
  32.     int_type* ito_next;
  33.     result r1;
  34.  
  35.     int size = strlen(e_lit);
  36.     int size2 = strlen(e_lit2);
  37.  
  38.     r1 = cvt->in(state01, e_lit, e_lit + size, efrom_next,
  39.                  i_arr, i_arr + size, ito_next);
  40.     if (r1 != codecvt_base::ok)
  41.         return -1;
  42.     for (int i = 0; i < size && i_arr[i]; ++i) {
  43.         if (i_arr[i] == 0×20000000) {
  44.             printf("\n");
  45.         } else {
  46.             printf("0x%08X\n", i_arr[i]);
  47.         }
  48.     }
  49.     cout << endl;
  50.  
  51.     r1 = cvt->in(state01, e_lit2, e_lit2 + size2, efrom_next,
  52.                  i_arr, i_arr + size2, ito_next);
  53.     if (r1 != codecvt_base::ok)
  54.         return -1;
  55.     for (int i = 0; i < size2 && i_arr[i]; ++i) {
  56.         if (i_arr[i] == 0×20000000) {
  57.             printf("\n");
  58.         } else {
  59.             printf("0x%08X\n", i_arr[i]);
  60.         }
  61.     }
  62.     cout << endl;
  63.  
  64.     return 0;
  65. }

실행 결과는 다음과 같다. 각각의 글자가 제대로 된 UCS4 워드값을 가지고 있음을 볼 수 있다.

0×9DC40000 // 쒝

0×8CC20000 // 슌

0×4CAF0000 // 꽌

0xDCC20000 // 시
0xC7B00000 // 냇
0×3CBB0000 // 물

0×98CC0000 // 처
0×78C80000 // 졸

0xC7B00000 // 냇

codecvt 대신에 mbstowcs()를 사용하게 되면 완성형 문자집합의 범위를 넘어서는 확장완성형 코드의 경우 ‘?’로 변환되어 ‘쒝’, ‘슌’, ‘꽌’ 등의 글자가 모두 같은 워드값을 가지게 되는 문제점이 나타난다.

다만 위 소스코드의 한 가지 아쉬운 점은 locale 설정, codecvt 생성, state 생성을 초기화하는 별개 함수로 분리할 수 없다는 점이다. state를 포인터나 레퍼런스로 넘기게 되면 cvt의 in() 메쏘드를 호출할 때 내부에서 segmentation fault가 발생한다. 아직 해결책을 찾지 못하고 같은 함수에서 사용하는 방법을 사용하고 있다.

<출처 : http://terzeron.net/wp/?p=733 >