C++でC風ライブラリを作る(UTF-8からUTF-16への変換編)
高木です。おはようございます。
前回は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のいずれかであることを仮定しています。
それではさっそくコードを書いていきましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | 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
型版を実装します。
1 2 3 4 5 6 7 8 9 | 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
型のサイズで振り分けているだけです。