CODE-配合VARCHAR長度截取字串
3 | 16,392 |
專案裡遇到的特殊需求,有個欄位在程式內部採用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#新手
正在煩惱要怎麼處理這個問題 想不到剛好能看到這個教學,還有完整程式碼跟說明 真是太謝謝了