CODE-配合VARCHAR長度截取字串
| | | 3 | |
專案裡遇到的特殊需求,有個欄位在程式內部採用Unicode編碼,但要匯出給某個系統接收時,中介資料表卻制定了採Big5編碼的VARCHAR(50)格式,這意味著:
1) Big5編碼的中文字元相當於VARCHAR(2),長度限制應為25個Unicode中文字元
2) 包含Unicode的字串在轉換後將變成"?"
原本系統採保守策略,把輸入欄位的長度限定在25個字元,不過客戶反應輸入內容常中英文交雜,英文字元也被視為2個Byte(在VARCHAR其實只佔1個Byte),讓可用字數變少,平白浪費讓說明文字更完整的機會。
所以需求來了: "文字長度限制應由NVARCHAR(25)放寬為VARCHAR(50),並可自動截除過長部分"! 其中的玄機在於英數符號在VARCHAR的長度只有中文的一半,所以若字串中有英數字或半形符號,便可輸入超過25個字。另外,若匯出時發現字串超長可以直接截除,需在後方加上"..."刪節號。
原則上用Encoding.GetEncoding(“big5”).GetBytes()將字串轉成byte[]便可精確計算轉為VARCHAR後的長度,再用GetString(byte[], 0, len)只取限定長度內容轉回字串即可完成自動截除。唯一的小技巧是在截斷時有可能切到中文字,只留下中文字的前一個Byte產生亂碼或問號。我想到的解決方法是用StartsWith比對完整轉換及截斷長度轉換出來的字串,若出現亂碼時,StartsWith會傳回false,此時將len - 1,再多截去殘留的半個中文字,就可以避免中文字被切一半的問題。
附上程式範例:
using System; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args)
{ string s = "ABC中文測試";
Console.WriteLine(TrimForBig5(s, 20, false)); Console.WriteLine(TrimForBig5(s, 8, false)); Console.WriteLine(TrimForBig5(s, 8, true)); Console.Read();
}
/// <summary> /// 將字串截至Big5編碼下的指定長度 /// </summary> /// <param name="s">輸入字串</param> /// <param name="len">指定長度</param> /// <returns>處理結果</returns> static string TrimForBig5(string str, int len, bool ellipsis)
{ Encoding big5 = Encoding.GetEncoding("big5"); byte[] b = big5.GetBytes(str); if (b.Length <= len) //未超長,直接傳回
return str; else { //如果要加刪節號再扣三個字元 if (ellipsis) len -= 3; string res = big5.GetString(b, 0, len); //由於可能最後一個字元可能切到中文字的前一碼形成亂碼 //透過截斷的亂碼與完整轉換結果會有出入的原理來偵測 if (!big5.GetString(b).StartsWith(res)) res = big5.GetString(b, 0, len - 1);
return res + (ellipsis ? "..." : "");
}
}
}
}
Comments
# by Ark
why not if (b.Length <= len) //未超長,直接傳回 ??
# by Jeffrey
to Ark, 是的,該處應寫成<=較佳,感謝提醒,已更正。
# by c#新手
正在煩惱要怎麼處理這個問題 想不到剛好能看到這個教學,還有完整程式碼跟說明 真是太謝謝了