亂碼 1/2:Unicode 字元不要用 char 型別來處理

最近在處理一些中文字的問題時,發現一個已經用了兩年多的程式,碰到一些特別罕見的中文字就無法正確執行。當初寫這個程式時,只有測試一般的 Unicode 字元,而沒有考慮到那些特別罕見的中文字。試看這個例子:

string str = "風";
char ch = s[0];
MessageBox.Show(ch.ToString());

不意外,畫面顯示的結果是 "風"。如果用 str.Length 來取字串長度,得到的結果也是預料中的 1。

對於一般常見或「稍微罕見」的中文字,上面的寫法並不會有問題。但如果碰到特別罕見的中文字就會出狀況了,例如這個:

string str = "𩗴";
char ch = str[0];
MessageBox.Show(ch.ToString());

輸出的結果是.....亂碼。



由於 Unicode 的總字數超過 65536 個字元,有些罕見字的編碼會超過 2 bytes,例如此例的「𩗴」(讀作四聲「ㄅㄥˋ」),這個字的編碼佔 4 bytes,若使用 str[0] 的方式取出第一個字元,就會只抓到整個 Unicode 字元的一半,因而出現亂碼--姑且叫它亂碼 1/2 :p (此例的 str.Length 是多少?)

有關 surrogate pairs 和 combining character sequences 的說明,這裡就偷懶跳過,寫程式時只需牢記:在 .NET 裡面,Unicode 字元必須以字串的方式處理

因此,前面的範例應該改成這樣:

string str = "𩗴";
string ch = StringInfo.GetNextTextElement(str);
MessageBox.Show(ch);

StringInfo 類別隸屬 System.Globalization 命名空間,其 GetNextTextElement 方法可以傳回第一個 Unicode 字元(注意型別是 string),或傳回特定索引位置的字元。詳細用法請參考 MSDN 線上文件

註:這篇的 "𩗴" 字,在網頁上輸入時,是寫成:
  𩗴
  這個數字可以經由呼叫 Char.ConvertToUtf32("𩗴") 得到。

2 則留言:

  1. 阿阿...此例的 str.length 居然是 2.
    叫我如何相信 str.length 呢 (淚)

    回覆刪除
  2. 呵...如果應用程式不太會碰到極罕見的漢字,倒是還 OK 啦。有些文字編輯器的軟體也無法正確處理這種雙字元組合成的罕見字。

    回覆刪除

技術提供:Blogger.
回頂端⬆️