C/C++에서 일본어를 다루고 싶습니다.

소개



C/C++에서는 일본어를 다루는 것이 어색한 문제가 된다.

bad_example1.c
#include <stdio.h>
#include <string.h>

int main() {
  char str[] = "日本語サンプル";
  int length = strlen(str);

  printf("1文字目: %c\n", str[0]);
  printf("長さ: %d\n", length);

  return 0;
}
$ gcc -o bad_example1 bad_example1.c
$ ./bad_example1
1文字目: �
長さ: 21

이와 같이 단순한 char형으로서 취급하면 일본어를 잘 처리할 수 없다. 뭐, 일본어가 2바이트 이상으로 표현되고 있기 때문에 당연하다고 하면 당연하지만.

그래서 C/C++에서 잘 일본어를 처리하는 방법을 두 가지 소개하고 싶다.

와이드 문자 사용



와이드 문자는 16 비트 고정 길이로 표현되는 다국어 문자 체형입니다.

C 언어에서는 wchar_t 타입을 사용하여 와이드 문자를 처리할 수 있다.

그러나 와이드 문자를 처리하려면 로케일 설정이 필요합니다. 일본어만 취급하는 경우는 ja_JP.UTF-8에 세트한다.

locale의 동작은 처리계 의존 같기 때문에, 아래의 코드는 Windows나 Mac에서는 정상적으로 동작하지 않을 가능성이 있습니다.

example1.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <locale.h>
#include <wchar.h>

int main() {
  setlocale(LC_CTYPE, "ja_JP.UTF-8");

  char str1[] = "(゚∀゚)( ゚∀)超( ゚)絶( )大(゚ )興(∀゚ )奮(゚∀゚)━キター!!!!";

  // 十分なメモリ領域を確保
  size_t capacity = strlen(str1) + 1;
  wchar_t *str2 = (wchar_t *)malloc(sizeof(wchar_t) * capacity);

  // char -> wchar_tの変換
  int result = mbstowcs(str2, str1, capacity);

  if (result <= 0) {
    fprintf(stderr, "マルチバイト文字列の変換に失敗\n");
    return EXIT_FAILURE;
  }

  printf("バイト長: %lu\n", capacity - 1);
  printf("長さ: %d\n", result);

  // 十分なメモリ領域を確保
  capacity = wcslen(str2) * 6 + 1;
  char* str3 = (char *)malloc(sizeof(char) * capacity);

  // wchar_t -> charの変換
  result = wcstombs(str3, str2, capacity);

  if (result <= 0) {
    fprintf(stderr, "ワイド文字列の変換に失敗");
    return EXIT_FAILURE;
  }

  printf("文字列: %s\n", str3);
  printf("1文字目: %lc\n", str2[0]);
}
$ gcc -o example1 example1.c
$ ./example5
バイト長: 86
長さ: 44
文字列: (゚∀゚)( ゚∀)超( ゚)絶( )大(゚ )興(∀゚ )奮(゚∀゚)━キター!!!!
1文字目: (

여러가지 조사했지만, UTF-8의 경우는 최대로 1 문자 6 바이트를 사용해 나타내지므로, char형으로 변환할 때는 6배의 메모리를 확보해 두면 문제 없다.

wchar_t형의 변수를 출력하는 경우, 문자의 경우의 서식 캐릭터 라인은 %lc, 캐릭터 라인의 경우는 %ls로 하면 된다.

그리고, wprintf나 wcout는, printf나cout와 병용하면 거동이 이상해지는 일이 있기 때문에, 가능한 한 사용하지 않는 편이 무난하다.

일단 char형으로 변환하고 나서 출력하는 것이 가장 안전할 것이다.

utfcpp 사용



이쪽은 C++ 한정이지만, wchar_t형으로 변환하지 않고 멀티 바이트 캐릭터 라인을 취급할 수 있으므로 편리.

utfcpp : htps : // 기주 b. 코 m / 네 mt f / u tfc p

이것을 사용하면, 문자열의 길이나 문자 위치의 이터레이터 등을 간단하게 구성할 수 있다.

example2.cpp
#include <iostream>
#include <cstring>
#include <cstdint>
#include <utf8.h>

int main() {
  const char* str1 = u8"明日天気にな〜れ";

  const char* it = str1;
  const char* end = str1 + strlen(str1);

  // 文字列の長さを取得
  int length = utf8::distance(it, end);
  std::cout << "長さ: " << length << std::endl;

  std::cout << std::hex;

  while (it < end) {
    // イテレータを1文字分すすめる
    std::uint32_t code = utf8::next(it, end);

    // 該当位置の文字コードを出力
    std::cout << code << std::endl;
  }

  return 0;
}
$ g++ example2.cpp -o example4
$ ./example2
長さ: 8
660e
65e5
5929
6c17
306b
306a
301c
308c

그 밖에도 편리한 함수가 많이 있으므로, Github 쪽을 참조해 주었으면 한다.

요약



C/C++에서도 일본어 취급할 수 있어!

좋은 웹페이지 즐겨찾기