ものがたり(旧)

atsushieno.hatenablog.com に続く

CompareOptions.IgnoreWidth

collation tableをランタイムのヘッダにしたらまずいだろう、って書いてたら、むしろランタイムのヘッダじゃないとエンディアンネスまわりで問題がある、というツッコミが入ってしまった。うーむ、確かにその通りだ。MS.NETってそういうところはお気楽だよなぁ。Windows環境だけ考えてりゃいいわけだし。

というわけでCヘッダを出力するコードをざっくりと書いてから、ふとushortの配列なんて実は消せるんじゃん?と思いついて、テーブルデザインの方を変えたら上手いことほぼ全部消えた。ていうかIgnoreWidthで影響を受ける文字が意外と少ない。あまりにも少ないのでロジックでコーディングしてしまった。


public static int ToWidthCompat (int i)
{
if (i < 0x2190) return i;
if (i > 0xFF00) {
if (i <= 0xFF5E) return i - 0xFF00 + 0x20;
switch (i) {
case 0xFFE0: return 0xA2;
case 0xFFE1: return 0xA3;
case 0xFFE2: return 0xAC;
case 0xFFE3: return 0xAF;
case 0xFFE4: return 0xA6;
case 0xFFE5: return 0xA5;
case 0xFFE6: return 0x20A9;
}
}
if (i > 0x32FE) return i;
if (i <= 0x2193) return 0xFFE9 - 0x2190 + i;
if (i < 0x2502) return i;
if (i <= 0x25CB) {
switch (i) {
case 0x2502: return 0xFFE8;
case 0x25A0: return 0xFFED;
case 0x25CB: return 0xFFEE;
default: return i;
}
}
if (i < 0x3000) return i;
if (i < 0x3131) {
switch (i) {
case 0x3000: return 0x20;
case 0x3001: return 0xFF64;
case 0x3002: return 0xFF61;
case 0x300C: return 0xFF62;
case 0x300D: return 0xFF63;
case 0x30FB: return 0xFF65;
default: return i;
}
}
if (i < 0x3164) return i - 0x3130 + 0xFFA0;
if (i == 0x3164) return 0xFFA0;
return i;
}
ただしこの中にはひらがなは含まれない。ひらがなの重みはIgnoreWidthの守備範囲だが、sortkeyのデータ領域はspecial weightなので、この関数の守備範囲外だ。ちなみにU+32D0-U+32FEのCircled HiraganaもIgnoreWidthの守備範囲内だったりする。謎だ。あともっと謎なのがSurrogate領域のsortkeyの値がなぜか変わってしまうことだ。

実はなぜなのかは分かっている。IgnoreWidthを指定されると、sortkeyのLevel 3の値から最後のビットが下りるのである。Level 3はcase weightなどとも言われているが、実際にはcaseとwidthの内容が共存している。一部のSurrogate文字はLevel 3の値が奇数なので、1削られてしまうということなのだ。