Top / .NET備忘録 / 11.文字列の扱い / 01.半角と全角

半角と全角を区別するのに、よく見かけるのが、Encoding.GetEncoding("SHIFT_JIS") を使って、GetByteCount で長さを見る方法。

これには欠点があって、シフト JIS に変換できない文字の中には、文字化けして 1 バイトになってしまうものがあります。

Dim enc As Encoding = Encoding.GetEncoding("SHIFT_JIS")
Debug.Print(enc.GetByteCount("佸"))

実行結果:1

解決するにはどうすればよいかというと、半角とみなす文字を格納した文字列や配列を作り、その中にあれば半角、なければ全角。というようにします。

VB の場合だと、Chr(0) 〜 Chr(255) がそれに当たります。

C# には、VB.NET のような、よさげな関数が無い(私が知らないだけ?)ので、Microsoft.VisualBasic.Chr を参考に、VBChr 関数を作成します。

// VB の Chr関数よりエラーチェックを外した部分
 public static char VBChr(int CharCode)
 {
     char chr;
     int chars;
     if (CharCode >= 0 && CharCode <= 127)
     {
         return Convert.ToChar(CharCode);
     }
     Encoding encoding = Encoding.GetEncoding(Thread.CurrentThread.CurrentCulture.TextInfo.ANSICodePage);
     char[] chrArray = new char[2];
     byte[] charCode = new byte[2];
     Decoder decoder = encoding.GetDecoder();
     if (CharCode < 0 || CharCode > 255)
     {
         charCode[0] = checked((byte)((CharCode & 65280) >> 8));
         charCode[1] = checked((byte)(CharCode & 255));
         chars = decoder.GetChars(charCode, 0, 2, chrArray, 0);
     }
     else
     {
         charCode[0] = checked((byte)(CharCode & 255));
         chars = decoder.GetChars(charCode, 0, 1, chrArray, 0);
     }
     chr = chrArray[0];
     return chr;
 }

これを使って配列を作ってソートし、

 private static char[] m_OneByteChars = InitialOnByteChars();
 
 private static char[] InitialOnByteChars()
 {
     char[] charArray = new char[256];
     for (int i = 0; i < 256; i++)
     {
         charArray[i] = VBChr(i);
     }
     Array.Sort<char>(charArray);
     return charArray;
 }

バイナリサーチします。

 public static bool IsHalfChar(this char charValue)
 {
     return (Array.BinarySearch<char>(m_OneByteChars, charValue) >= 0);
 }

後日談

Encoding.GetEncoding は、.NET2.0 からエンコードに失敗したときのエラープロシジャを指定できるオーバーロードメソッドが追加されています。

これを使って、エンコードに失敗したキャラクタを2バイト文字に変換すれば、GetByteCount でよかったのですねorz

まぁ、256 要素をバイナリサーチしたほうが速いはずだよね・・・と思ってたら、速度でも負けていたという・・・(=_=)

 static CultureInfo s_CultureInfo = Thread.CurrentThread.CurrentCulture;
 static Encoding s_ShiftJisEncoding = Encoding.GetEncoding(s_CultureInfo.TextInfo.ANSICodePage,
                                                             new EncoderReplacementFallback("■"),
                                                             new DecoderReplacementFallback("■"));
 static Encoder s_ShiftJisEncoder = s_ShiftJisEncoding.GetEncoder();
 
 public unsafe static bool IsHalfChar2(this char value)
 {
     return s_ShiftJisEncoder.GetByteCount(&value, 1, true) == 1;
 }

バイナリサーチの部分を unsafe コードを使って書き換えれば速いのかもしれませんがバグってしまいそうなのでやめておきます。( `ー´)ノ




トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   最終更新のRSS
Last-modified: 2013-11-27 (水) 00:28:03 (1358d)