スポンサーリンク

ICUライブラリBreakIteratorでutf16を一文字ずつ表示する方法いくつか

void WinPaint(HWND hWnd) {

  // 元の文字列の定義
  std::u16string u16s = u"aあغ山👨‍👧經经";

  /////////////////////////////
  // ICUの設定

  icu::UnicodeString usr(u16s.c_str());

  UErrorCode err;
  icu::BreakIterator* bi = icu::BreakIterator::createCharacterInstance(
    icu::Locale::getDefault(),err);
  bi->setText(usr);

  ////////////////////////////
  //フォトの設定
  HDC hdc;
  PAINTSTRUCT ps;
  hdc = BeginPaint(hWnd, &ps);
  SetTextColor(hdc, RGB(0, 0, 0));  //文字の色を設定
  SetBkColor(hdc, RGB(230, 230, 230));  //文字の背景色を設定
  HFONT backup = (HFONT)SelectObject(hdc, hFont1);  //Step2  フォントを適応
  TEXTMETRIC tm;
  GetTextMetrics(hdc, &tm);
  int TH = 10;
  ////////////////////////////
  //文字を一文字(書記素)ずつ表示

  int32_t current = bi->first();
  while (current != icu::BreakIterator::DONE) {

    // 文字の長さを知る必要があるので、
    // 「現在の文字の位置」と「前の文字の位置」が必要
    int32_t prev = current;
    current = bi->next();

    if (current == UBRK_DONE) {
      break;
    }

    int32_t count = current - prev;//文字の長さ

    TextOutW(hdc, 10, TH, (WCHAR*)& usr.getBuffer()[prev], count);//文字を書く
    //改行
    TH += tm.tmHeight+5;
  }
  SelectObject(hdc, backup);

  EndPaint(hWnd, &ps);
}

一文字表示する部分の記述方法

    TextOutW(hdc, 10, TH, (WCHAR*)& usr.getBuffer()[prev], count);//文字を書く
    icu::UnicodeString e;
    usr.extract(prev, count, e);
    // win32api のWCHARはutf16なのでただキャストするだけで変換できる
    TextOutW(hdc, 10, TH, (WCHAR*)e.getBuffer(), e.length());//文字を書く
    // substr(現在位置,切り取る長さ)
    std::u16string sub = u16s.substr(prev, count);
    TextOutW(hdc, 10, TH, (WCHAR*)sub.data(), count);//文字を書く

なおなぜかWordpressのせいでサロゲートペアが入力できないのでサンプルから抜いている。

prev,currentの変化

first(),next()で操作するのはchar16_tとしての配列の要素番号。なので+1移動で2Byte移動だが、サロゲートペアや結合文字があった場合はその限りではない。

コメントを残す

メールアドレスが公開されることはありません。

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: