がりらぼ

WindowsRuntimeの応援ブログ

𩹉(とびうお)問題

「𩹉」という文字、(とびうお)というんですね...初めて知りました。
C#で文字列処理をする場合、Stringクラスを使うと思うんですが、Stringクラスは基本的に2バイト文字までを考えて設計されているので𩹉みたいなバイト数の多い文字が来たときは正しく処理ができません。

文字によってサイズが違うとStringクラスが間違った処理をしちゃうんですね。

では各文字のサイズを見てみましょう。
文字サイズは
文字数 カウント(文字バイト数チェック)
で調べることができます。

まずは英数字
f:id:garicchi:20140119153649p:plain

当然のごとく1バイトですね。

次に日常でよく使うような感じ
f:id:garicchi:20140119153722p:plain

日常でよく使うような漢字は2バイトで表現できるので当然2バイトですね。
Stringクラスであつかえるのはここまでです。

つづいて𩹉(とびうお)
f:id:garicchi:20140119153808p:plain

9バイト...そうとう後から追加されたんですね...すごくサイズが大きいです。

じゃあC#のStringクラスで2バイト以上の文字を扱おうとするとどうなるのかというと、

こんなコードの場合

string tobiuo = "俺が𩹉だ";
            Debug.WriteLine("文字数="+tobiuo.Length);
            Debug.WriteLine("とびうお抽出=" + tobiuo.Substring(2, 1));

「俺が𩹉だ」という文字は4文字、また𩹉は0から数えて2文字目にあるのでSubStringで抽出できるはずです。

結果はこうなりました。

文字数=5
とびうお抽出=☐

文字数が5になってますね...
抽出文字にいたっては何を抽出したのかわかりません。
このように2バイト文字以上はStringクラスだけでは扱うことができません。


そんなときに便利なStringInfoクラスがあります。
StringInfo クラス (System.Globalization)

StringInfoクラスのLengthInTextElementsプロパティを使うと要素の正しい文字数を返してくれます。
SubstringByTextElementsメソッドは正しい位置の文字を抽出してくれます。

こんな感じ

string tobiuo = "俺が𩹉だ";
StringInfo info = new StringInfo(tobiuo);
            Debug.WriteLine("SrtingInfoから見た文字数"+info.LengthInTextElements.ToString());
            Debug.WriteLine("StringInfoとびうお抽出=" + info.SubstringByTextElements(2,1));

出力

SrtingInfoから見た文字数4
StringInfoとびうお抽出=𩹉

オッケ


これでいじわるリプライにも対応できますね!