C++11から導入されたchar16_t型は、<uchar>で__STDC_UTF_16__マクロが定義されている場合にUTF-16のコードポイントを保持する文字型になります。ただし、C++20からは__STDC_UTF_16__の定義状態にかかわらずUTF-16になりました。現実問題として、C++11からC++17でもUTF-16だと仮定してしまっても実用上は問題ないと考えられます。
今回はC++11以降を前提に、char16_t型がUTF-16を表すと仮定して各種関数を定義していきたいと思います。また、話を簡単にするために、今回はint型が32ビットであると仮定することにします。
最初に下準備として、必要な定数を定義します。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// サロゲート領域の定義 constexpr char16_t high_surrogate_min = 0xd800; // 上位サロゲート領域開始位置 constexpr char16_t high_surrogate_max = 0xdbff; // 上位サロゲート領域終了位置 constexpr char16_t low_surrogate_min = 0xdc00; // 下位サロゲート領域開始位置 constexpr char16_t low_surrogate_max = 0xdfff; // 下位サロゲート領域終了位置 constexpr char16_t surrogate_min = high_surrogate_min; // サロゲート領域開始位置 constexpr char16_t surrogate_max = low_surrogate_max; // サロゲート領域終了位置 // サロゲート可変部分のビット数(上位,下位共通) constexpr int surrogate_bits = 10; // サロゲート符号単位の可変部分を抽出するためのマスク constexpr int high_surrogate_mask = (1 << surrogate_bits) - 1; // 上位用 constexpr int low_surrogate_mask = (1 << surrogate_bits) - 1; // 下位用 constexpr int both_surrogate_mask = (1 << (surrogate_bits + 1)) - 1; // 上下用 |
以下、この定数を使って関数を実装していきます。
UTF-16の符号単位が上位サロゲートか否かを判定する。
0 1 2 3 4 5 |
constexpr bool is_high_surrogate(char16_t c) { return (c & ~high_surrogate_mask) == high_surrogate_min; } |
UTF-16の符号単位が下位サロゲートか否かを判定する。
0 1 2 3 4 5 |
constexpr bool is_low_surrogate(char16_t c) { return (c & ~low_surrogate_mask) == low_surrogate_min; } |
UTF-16の符号単位が上位または下位サロゲートか否かを判定する。
0 1 2 3 4 5 |
constexpr bool is_surrogate(char16_t c) { return (c & ~both_surrogate_mask) == surrogate_min; } |
UTF-16の2つの符号単位の組 (first,second) がサロゲート・ペアか否かを判定する。
0 1 2 3 4 5 |
constexpr bool is_surrogate_pair(char16_t first, char16_t second) { return is_high_surrogate(first) && is_low_surrogate(second); } |