2-25 Update:經網友 Laneser 提醒,其實這篇提到的問題用 HtmlDecode 就簡單解決掉啦! 裡面提到的函式大概就只剩下 FindUnicodeEntities 可能還有用處吧! 其他一長串的東西就不用浪費時間看啦!
本來資料庫和 ASP.NET 環境都支援 Unicode,顯示 Unicode 字元應該沒甚麼問題的,但這次碰到的問題,是網頁顯示的資料來自另一個舊系統的資料庫,而那個資料庫原本儲存的資料都是 BIG-5 編碼。該舊系統是以 ASP 撰寫,為了能夠在網頁上正常顯示 Unicode 字元,它在存入資料庫時,會將 Unicode 字元存成內碼的形式,例如日文「に」這個字,舊系統會將它存成 "に"。如此一來,瀏覽器看到 "に",就會將它轉換成「に」,使用者就能看到正確的字元了。舊系統的這種作法不需要甚麼特別的額外處理,因為轉換和顯示的部分是由瀏覽器代勞了。但由於新系統是走 ASP.NET 平台,資料庫均採用 UTF-8 編碼,這就衍生一些問題出來了。
比如說,ASP.NET 的 GridView 控制項預設會針對網頁環境而將欲顯示的字串做 HTML 編碼的動作,如果不將欄位物件(BoundField)的 HtmlEncode 屬性設為 False,在顯示上述舊系統的資料時就會看到 "に" 而不是「に」。
GirdView 還好辦,TextBox 控制項就麻煩了,因為它預設會自動處理 HTML 編碼形式的 Unicode 字串,卻沒有提供 HtmlEncode 屬性。以下是一個簡單的 ASP.NET 範例程式,可以測試這個問題:
畫面上有一個 Label 和兩個 TextBox,我在程式裡分別用 Response.Write 直接輸出的方式,以及丟給 Label1、TextBox1、和 TextBox2 來顯示 "に" 所代表的字元。執行結果如下:
最簡單的解法似乎是捨棄 TextBox 控制項,改用其他自訂的文字輸入元件,但如果程式都寫好了,有數百個控制項需要替換,這....還是挺麻煩的。
另一個辦法,就是寫一個 HTML「解碼」函式,能夠搜尋字串中以 '&# ' 開頭的部分,將之替換成 Unicode 字元。結果就寫了這三個工具函式來處理:
使用方法很簡單,像這樣:
如果要使用前面的程式碼,請記得 using System.Text 和 System.Text.RegularExpressions 喔!
Happy coding :)
本來資料庫和 ASP.NET 環境都支援 Unicode,顯示 Unicode 字元應該沒甚麼問題的,但這次碰到的問題,是網頁顯示的資料來自另一個舊系統的資料庫,而那個資料庫原本儲存的資料都是 BIG-5 編碼。該舊系統是以 ASP 撰寫,為了能夠在網頁上正常顯示 Unicode 字元,它在存入資料庫時,會將 Unicode 字元存成內碼的形式,例如日文「に」這個字,舊系統會將它存成 "に"。如此一來,瀏覽器看到 "に",就會將它轉換成「に」,使用者就能看到正確的字元了。舊系統的這種作法不需要甚麼特別的額外處理,因為轉換和顯示的部分是由瀏覽器代勞了。但由於新系統是走 ASP.NET 平台,資料庫均採用 UTF-8 編碼,這就衍生一些問題出來了。
比如說,ASP.NET 的 GridView 控制項預設會針對網頁環境而將欲顯示的字串做 HTML 編碼的動作,如果不將欄位物件(BoundField)的 HtmlEncode 屬性設為 False,在顯示上述舊系統的資料時就會看到 "に" 而不是「に」。
GirdView 還好辦,TextBox 控制項就麻煩了,因為它預設會自動處理 HTML 編碼形式的 Unicode 字串,卻沒有提供 HtmlEncode 屬性。以下是一個簡單的 ASP.NET 範例程式,可以測試這個問題:
1: protected void Page_Load(object sender, EventArgs e)
2: {
3: string s = "に"; // 'に'
4: Response.Write(s + "<BR/>"); // OK!'
5: Label1.Text = s; // OK!'
6:
7: // TextBox 內建 HTML encoding 功能,反而無法秀出 unicode 代碼所表示的字元.
8: TextBox1.Text = s;
9:
10: // 經過轉換就 ok 了.
11: TextBox2.Text = Convert.ToChar(Convert.ToInt32(s.Substring(2, 5))).ToString();
12: }
最簡單的解法似乎是捨棄 TextBox 控制項,改用其他自訂的文字輸入元件,但如果程式都寫好了,有數百個控制項需要替換,這....還是挺麻煩的。
另一個辦法,就是寫一個 HTML「解碼」函式,能夠搜尋字串中以 '&# ' 開頭的部分,將之替換成 Unicode 字元。結果就寫了這三個工具函式來處理:
1: /// <summary>
2: /// 將 Unicode 的 HTML 碼轉換成 Unicode 字元。
3: /// <para>C# 範例:<</para>
4: /// <p>char ch = UnicodeEntityToChar("に");
5: /// </p>
6: /// </summary>
7: /// <param name="entity">Unicode 的 HTML 碼。</param>
8: /// <returns>字元。</returns>
9: public static char UnicodeEntityToChar(string entity)
10: {
11: int code = Convert.ToInt32(entity.Substring(2, entity.Length - 3));
12: return Convert.ToChar(code);
13: }
14:
15: /// <summary>
16: /// 找出指定字串中的所有 Unicode HTML 碼。
17: /// </summary>
18: /// <param name="s">輸入字串。</param>
19: /// <returns>所有找到的 Unicode HTML 碼的集合。</returns>
20: public static MatchCollection FindUnicodeEntities(string s)
21: {
22: string pattern = @"&\#[0-9]{1,5};";
23: Regex regex = new Regex(pattern);
24: MatchCollection matches = regex.Matches(s);
25: return matches;
26: }
27:
28:
29: /// <summary>
30: /// 將傳入字串中的 Unicode 字碼(� 格式)轉換成實際的 Unicode 字元。
31: /// </summary>
32: /// <param name="s">傳入字串。</param>
33: /// <returns>已轉換完成的字串。</returns>
34: public static string ReplaceUnicodeEntityToChar(string s)
35: {
36: StringBuilder result = new StringBuilder(s);
37: MatchCollection matches = FindUnicodeEntities(s);
38:
39: // Note: 不可從第一個符合的項目開始替換字串,須倒著處理.
40: for (int i = matches.Count-1; i >= 0; i--)
41: {
42: Match m = matches[i];
43: result.Remove(m.Index, m.Length);
44: result.Insert(m.Index, UnicodeEntityToChar(m.Value));
45: }
46: return result.ToString();
47: }
使用方法很簡單,像這樣:
1: string test = "這是日文:に,再一個:に,再兩個:にに";
2: string s = ReplaceUnicodeEntityToChar(test);
3: Response.Write(s + "<BR/>") ;
Happy coding :)
why not use HttpUtility.HtmlDecode ??
回覆刪除Hi Laneser,
回覆刪除對耶!我怎麼都沒想到 HtmlEncode 對應的就是 HtmlDecode 啊!蠢極了 @_@||
這篇文章應該刪掉的,但我想還是留著,為我這次的愚蠢作個紀念和警惕吧!
Thanks!!
格主太精實了, 讓我忍不住拿壓箱寶跟格主獻醜, 以下是我做的類似 code:
回覆刪除private static Regex reg = new Regex(@"&\#([0-9]{1,5});", RegexOptions.Compiled);
public static string HtmlDecode(string content)
{
return reg.Replace(content, m => Convert.ToChar(Convert.ToInt32(m.Groups[1].Value)).ToString());
}
您客氣啦,一般的說法是「老實」 ^_^
回覆刪除很感謝您的壓箱寶分享,取 Groups 的寫法簡潔多了,省去拆字串的工夫。
又學到一招,多謝多謝 :)