0.異体字セレクタとは
非常に大雑把かつ乱暴に言うと、山ほどある異体字を表示させるための仕組みのひとつ。
文字にいちいち固有の番号を割り当てるのではなく、番号に枝番号(符号)を付ける仕掛けである。
対応するフォントが必要だが、Windowsに標準添付の一部フォントでもそれなりに対応している。
詳しくはWikipediaなど参照してもらった方がいい。
Windows7からメモ帳でも利用可能になったので試してみた人も多いかもしれない。
1.表示は簡単
とりあえずよくある「1点しんにょうの辻」をTEditに表示する。
フォームにTEditとTButtonを一つずつ貼り付け、TEditのフォントはMS 明朝、フォントサイズは判別しやすいように30にしておく。
以下の数行のコードで、1点しんにょうの辻が表示される。
1 2 3 4 5 6 7 8 9 10 |
void __fastcall TForm1::Button1Click(TObject *Sender) { wchar_t wc[4]; wc[0] = 0x8FBB; // 「辻」のコード番号 wc[1] = 0xDB40; // 枝番の上位2byte wc[2] = 0xDD00; // 枝番の下位2byte wc[3] = L'\0'; Edit1->Text = wc; } |
このように表示される。
2.仕組みとか
異体字セレクタは、通常の文字番号に、0xE0100から始まる枝番号を付けることで作動する。(最大で240までの枝番号が付けられるが、実際にそんなにたくさんの枝番号が定義された文字は現在ない。)
0xE0100は2byteで収まらないので、当然、wchar_tに格納できない。(C++Builderはwchar_tが2byte)
が、上位2byteは0xDB40で固定。下位2byteに0xDD00~0xDDEFまでのいずれかを格納してやればよい。
なお存在しない枝番を指定した場合、単に標準の文字が表示される。
3.フォントによって異なる枝番号
どの枝番号にどの異体字形が割り振られているかは、実はフォントによって違う。(正確に言うとフォントによって採用している字形コレクションが違う)。
異なるフォントを設定した3つのMemoに、「辻」の異体字の枝番を順に表示してみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
void __fastcall TForm1::Button4Click(TObject *Sender) { // 空かサロゲート文字なら終了 if( Edit->Text.IsEmpty() || IsSurrogate( Edit->Text, 1 ) ) return; Memo1->Lines->Clear(); Memo2->Lines->Clear(); Memo3->Lines->Clear(); // std::wstring wstr = Edit->Text.c_str(); wchar_t wc[4]; wc[0] = wstr[0]; wc[1] = 0xDB40; // 0xE0100 の上位バイト wc[3] = L'\0'; for( int i = 0; i < 3; ++i ) { wc[2] = 0xDD00 + i; String Str = wc; Memo1->Lines->Add( Str ); Memo2->Lines->Add( Str ); Memo3->Lines->Add( Str ); } } |
実行結果
1点しんにょうの辻は、IPAmj明朝の場合は3番目、游明朝およびMS明朝なら1番目に割り振られているのが分かる。
いったん表示した後、フォントを変えると、文字が変化してしまう危険がある。
4.1文字で3文字分
文字数を数えるプログラムなどでは注意が必要。
SystemのLength()でもstd::wstringのlength()でも、3文字になる。
サロゲートペアの判定はIsSurrogateで簡単だが、異体字セレクタの場合はもう一工夫必要になるはず。
5.TMemoとTRichEditで挙動が異なる
異体字セレクタ文字は、TMemoとTRichEditで挙動・表示が違う。
1点しんにょうの辻と通常の辻の2文字をそれぞれ表示してみる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
void __fastcall TForm1::Button3Click(TObject *Sender) { // ノーマルな文字 String NoIvsStr( L"辻" ); // 異体字セレクタを利用した文字の作成 std::wstring no_ivs_str = NoIvsStr.c_str(); // 作成用に利用 wchar_t wc[4]; wc[0] = no_ivs_str[0]; wc[1] = 0xDB40; wc[2] = 0xDD00; wc[3] = L'\0'; String IvsStr = wc; // IVS使用の異体字と通常文字を足す String NewStr = IvsStr + NoIvsStr; // MemoとRichEditに表示 Memo->Text = NewStr; RichEdit->Text = NewStr; } |
実行結果。左がTMemo, 右がTRichEdit。
このようにRichEditは枝番分の文字の空きが取られてしまう。
ちなみに、この空きをキーボードで削除すると
枝番情報が消えるので最初の文字が通常の「辻」に戻ってしまう。
また、Memoの方でも、1点しんにょうの辻の後ろにカーソルを置きBackSpaceキーを押すと、文字は消えないがやはり先祖返りする。
以上、基本的にVclとFireMonkey共通。(ただしFireMonkeyにはRichEditはない。)
C++Builder10.2.3 / Windows10 で確認。