potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

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