C++でC風ライブラリを作る(UTF-8からUTF-32への変換編)
高木です。
前回まではUTF-16やUTF-32からUTF-8への変換を行う関数を作りました。
今回からはその逆で、UTF-8からUTF-16やUTF-32への変換を行いたいと思います。
見た目、ちょっと紛らわしいので注意してください。
すべてを一気に実装するのは大変ですので、まずはUTF-8からUTF-32に変換するmbrtoct
関数を作ることにします。
その後、UTF-16版のmbrtoct
関数を作成し、続いてそれぞれのmbtoct
関数を作るという流れで行きたいと思います。
とはいえ、UTF-8からUTF-32に変換するmbrtoct
関数だけでもいろいろ考えないといけないことがあり大変です。
何が一番大変かというと、UTF-8が途中で終わっていた場合にmbstate_t
型のオブジェクトに状態を保存して再開できるようにしないといけないところです。
今回は、完全なUTF-8が与えられた場合だけを考えることにします。
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 39 40 41 42 43 44 45 46 47 | namespace cloverfield { inline std::size_t mbrtoct(char32_t* pc32, char const* s, std::size_t n, mbstate_t* ps) { int c = static_cast<unsigned char>(*s); char32_t c32; std::size_t r; if (c < 0x80) { c32 = c; r = 1; } else if ((c & 0xe0) == 0xc0) { c32 = (c & 0x1f) << 6 | s[1] & 0x3f; if (c32 < 0x80) r = -1; else r = 2; } else if ((c & 0xf0) == 0xe0) { c32 = (c & 0xf) << 12 | (s[1] & 0x3f) << 6 | s[2] & 0x3f; if (c32 < 0x800) r = -1; else r = 3; } else if ((c & 0xf8) == 0xf0) { c32 = (c & 0x7) << 18 | (s[1] & 0x3f) << 12 | (s[2] & 0x3f) << 6 | s[3] & 0x3f; if (c32 < 0x10000 || 0x10ffff < c32) r = -1; else r = 4; } else { r = -1; } if (pc32 != nullptr) *pc32 = c32; return r; } } |
というわけで、今回はいったん素直に作ってみました。
n
でさえ使っていない簡易的なものです。
今回の結果を踏まえつつ、次回はより完成に近い形まで持っていきたいと考えています。