(2018.9) 新規作成.
wxWidgets 3.0 になって, 文字列が Unicode ベースになった。しかしながら、ビルドオプションを考慮しなければならず、微妙に面倒になっている.
wxString
クラス
wxWidgets 3.0 の文字列は, Unicode "Code Point" (32bit) 単位ではない。"Code Unit" 単位で扱われる。
Unicode は "文字" が Code Point と一致していない。1文字が複数の Code Point になりうるし、逆もありうる.
https://www.unicode.org/reports/tr17/
最近では Unicode 異体字シーケンス (Ideographic Variation Sequence; IVS) が導入され、漢字も1 code point とは限らない。親字の後に Variation Selector (VS; 字形選択子) を続けて、字形を選択する. この符号列を Ideographic Variation Sequence という。
wxWidgets 3.0 では, ビルドオプションにより, 文字列の内部表現が UTF-32, UTF-16 または UTF-8 のいずれかになる。Windows では UTF-16, UNIX (Linux) では UTF-32 または UTF-8.
アプリケーション開発者は、ポータブルにするためには, 3つとも対応する必要がある。
UTF-16 | 一つの code point が, 1つまたは 2つの wchar (code unit) に
なる.
|
UTF-8 | 一つの code point (21bit) が 1-4 バイト (code unit) になる.
|
必要な場所では、次のようにして判定しなければならない。wchar_t
の大きさは、WCHAR_MAX
マクロで判定するのがもっともポータブルだろう。
wxUSE_UNICODE_WCHAR
マクロは、定義される・未定義ではなく、1 or 0 なので、#if
を使う。
C++
-
- #if wxUSE_UNICODE_WCHAR
-
-
- #if WCHAR_MAX >= 0x10000L
-
- #else
-
- #endif
- #else
-
-
- #endif
例
サンプルプログラムを書いてみる。
まず, バイト列から wxString
インスタンスを作るには, FromUTF8()
を使う.
C++
- int main()
- {
-
-
-
-
-
-
- wxString str = wxString::FromUTF8("ABCあいう漢字🚁");
-
-
- printf("length = %d\n", str.length());
-
-
- for(wxString::const_iterator p = str.begin(); p != str.end(); p++)
- printf("%x ", *p);
- printf("\n");
-
-
-
- printf("%d\n", str.Find("BC"));
- printf("%d\n", str.Find(wxString::FromUTF8("漢")) );
-
- printf("%d\n", str.Find(wxString::FromUTF8("愛")) );
Unicode 文字列を扱う場合, データベースに格納する直前に正規化するのがセオリー. しかし, wxString
は Unicode 特有の処理がほぼできないので、ICU と組み合わせる.
正規化はnormalize()
呼び出しだけなのに, 行ったり来たりが面倒。ヘルパー関数を作ったりするんだろう。
C++
-
-
- wxString str2 = wxString::FromUTF8("㎞㍻㍿");
-
- std::string x;
- #if wxUSE_UNICODE_WCHAR
- #if WCHAR_MAX >= 0x10000L
-
-
- UnicodeString us = UnicodeString::fromUTF32( (UChar32*) str2.wc_str(),
- str2.length() );
- us.toUTF8String(x); printf("%s\n", x.c_str());
- #else
- UnicodeString us(str2.wc_str());
- #endif
- #else
- UnicodeString us = UnicodeString::fromUTF8(
- static_cast<const char*>(str2.utf8_str()) );
- #endif
-
- UErrorCode err;
- u_init(&err);
-
- const icu::Normalizer2* norm = icu::Normalizer2::getNFKDInstance(err);
- UnicodeString normalized = norm->normalize(us, err);
- x = "";
- normalized.toUTF8String(x); printf("%s\n", x.c_str());
-
-
- #if wxUSE_UNICODE_WCHAR
- #if WCHAR_MAX >= 0x10000L
- wxString n;
- normalized.toUTF32( (UChar32*) static_cast<wchar_t*>(wxStringBuffer(n, 1000)),
- normalized.length() + 1, err );
- #else
- wxString n = normalized.getBuffer();
- #endif
- #else
- wxString n;
-
- std::string nn;
- normalized.toUTF8String(nn);
- n = wxString::FromUTF8(nn.c_str());
- #endif
-
- for(wxString::const_iterator p = n.begin(); p != n.end(); p++)
- printf("%x ", *p);
- printf("\n");
-
- return 0;
- }
Makefile はこんな感じ.
CXX = gcc
CXXFLAGS = -Wall `wx-config --cflags` `pkg-config --cflags icu-uc icu-io`
LDFLAGS = `wx-config --libs` `pkg-config --libs icu-uc icu-io` -lstdc++
wx3-string: wx3-string.o
wx3-string.o: wx3-string.cc