大阪市中央区 システムソフトウェア開発会社

営業時間:平日09:15〜18:15
MENU

C++でC風ライブラリを作る(UTF-8からUTF-16への変換編)

著者:高木信尚
公開日:2019/05/12
最終更新日:2019/05/11
カテゴリー:技術情報

高木です。おはようございます。

前回はUTF-8からUTF-32への変換でした。
今回はそれを利用してUTF-8からUTF-16に変換するためのmbrtoct関数を多重定義することにしましょう。

UTF-16にはchar16_t型を使用します。
以前からの方針として、char16_t型はUTF-16を扱うものと仮定しています。

さらに、wchar_t型にも対応することにしましょう。
wchar_t型の内部表現はUTF-16またはUTF-32のいずれかであることを仮定しています。

それではさっそくコードを書いていきましょう。

namespace cloverfield
{
  inline std::size_t mbrtoct(char16_t* pc16, char const* s, std::size_t n, mbstate_t* ps)
  {
    char32_t c32;
    char16_t c16;
    std::size_t r = -1;

    if (ps == nullptr)
      ps = detail::default_mbstate();

    if (ps->state > 0xffff)
    {
      c16 = (ps->state - 0x10000) & 0x3ff | 0xdc00;
      r = 0;
      goto quit;
    }

    r = mbrtoct(&c32, s, n, ps);
    if (r == std::size_t(-2))
      return r;

    if (c32 < 0x10000)
    {
      c16 = static_cast<char16_t>(c32);
      ps->state = c16;
    }
    else
    {
      c16 = (c32 - 0x10000) >> 10 | 0xd800;
    }

quit:
    if (pc16 != nullptr)
      *pc16 = c16;
    return r;
  }
}

素直な実装ですが、一点だけ工夫があります。
サロゲートペアが必要になる場合がそうです。

いったんUTF-32に変換し、その結果がU+10000以上だった場合、その時点ではサロゲートペアの上位側を結果とします。
ps->stateにはUTF-32をそのまま格納し、次に呼び出したときにサロゲートペアの下位側を結果として返せるようにします。
サロゲートペアの下位側を返す際には、mbrtoct関数の返却値は0とします。

次はwchar_t型版を実装します。

namespace cloverfield
{
  inline std::size_t mbrtoct(wchar_t* pwc, char const* s, std::size_t n, mbstate_t* ps)
  {
    if (sizeof(wchar_t) == sizeof(char16_t))
      return mbrtoct(reinterpret_cast<char16_t*>(pwc), s, n, ps);
    return mbrtoct(reinterpret_cast<char32_t*>(pwc), s, n, ps);
  }
}

ctrtomb関数のときと同じで、wchar_t型のサイズで振り分けているだけです。

    上に戻る