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がサロゲートペアを含むことが関与しています。
- Windows環境ではワイド文字が16ビット
ワイド文字(wchar_t
)のサイズは環境依存で、Windowsでは16ビット、LinuxやmacOS環境では32ビットだそうです。したがって、Windows開発ではワイド文字/文字列は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::iswgraph
がfalse
になる理由もこれに関連しています。
std::iswgraph
はwchar_t
型の引数を取り、wchar_t
はWindows環境では16ビット整数です。std::iswgraph
は与えられた引数だけで文字のタイプを判断するため、サロゲートペアの上位・下位を別々に与えられると指すものが分からずfalse
を返していると考えられます。