potisanのプログラミングメモ

プログラミング素人です。昔の自分を育ててくれたネット情報に少しでも貢献できるよう、情報を貯めていこうと思っています。Windows環境のC++やC#がメインです。

C++ Windows環境で絵文字のstd::iswgraphがfalseな理由の考察

VC++ではワイド文字列(L"...")に絵文字を含めることができます。この文字列に対してstd::iswgraphを適用しても戻り値はfalseです。

#include <string>
#include <cwctype>
#include <iostream>
#include <iomanip>

int main()
{
    const std::wstring s{ L"🍊🍎😁" };
    for (auto i = s.cbegin(); i != s.cend(); i++)
    {
        auto c = *i;
        std::wcout
            << L"0x" << std::hex << std::setfill(L'0') << std::setw(4) << static_cast<size_t>(c)
            << L" : " << std::boolalpha << !!std::iswgraph(c) << std::endl;
    }
}

出力結果

0xd83c : false
0xdf4a : false
0xd83c : false
0xdf4e : false
0xd83d : false
0xde01 : false

この背景にはWindowsではワイド文字が16ビットであることとUTF-16サロゲートペアを含むことが関与しています。

  1. Windows環境ではワイド文字が16ビット

ワイド文字(wchar_t)のサイズは環境依存で、Windowsでは16ビット、LinuxmacOS環境では32ビットだそうです。したがって、Windows開発ではワイド文字/文字列はUTF-16を指します。

  1. UTF-16サロゲートペアを含む

Unicode 11.0.0ではコードポイント(文字などに対応する番号)として0x0~0x10ffffffが予約されています。一方、UTF-16は16ビットなので0x0~0xffffしか表現できません。UTF-16で0x10000以上のコードポイントを表すため、サロゲートペアと呼ばれる方法が導入されています。

サロゲートペアはUTF-16で使われていなかった2つの領域を上位サロゲート、下位サロゲートとして予約し、上位サロゲートと下位サロゲートのペアで1つのコードポイントを表す方法です。

UTF-16はよく使う文字は16ビット、たまに使われる文字は32ビット(サロゲートペア)で表せるのでUTF-32よりもデータサイズに優れるメリットを持ちますが、扱いの複雑さをデメリットに持ち、Windows環境で絵文字のstd::iswgraphfalseになる理由もこれに関連しています。

std::iswgraphwchar_t型の引数を取り、wchar_tWindows環境では16ビット整数です。std::iswgraphは与えられた引数だけで文字のタイプを判断するため、サロゲートペアの上位・下位を別々に与えられると指すものが分からずfalseを返していると考えられます。

参考:Unicode - Wikipedia