CODE-配合VARCHAR長度截取字串

專案裡遇到的特殊需求,有個欄位在程式內部採用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 ? "..." : "");
            }
        }
 
    }
}
歡迎推文分享:
Published 05 July 2011 08:03 AM 由 Jeffrey
Filed under: ,
Views: 15,256



意見

# Ark said on 22 July, 2011 05:21 AM

why not

if (b.Length <= len) //未超長,直接傳回 ??

# Jeffrey said on 22 July, 2011 04:53 PM

to Ark, 是的,該處應寫成<=較佳,感謝提醒,已更正。

# c#新手 said on 30 June, 2016 11:33 PM

正在煩惱要怎麼處理這個問題

想不到剛好能看到這個教學,還有完整程式碼跟說明

真是太謝謝了

你的看法呢?

(必要的) 
(必要的) 
(選擇性的)
(必要的) 
(提醒: 因快取機制,您的留言幾分鐘後才會顯示在網站,請耐心稍候)

5 + 3 =

搜尋

Go

<July 2011>
SunMonTueWedThuFriSat
262728293012
3456789
10111213141516
17181920212223
24252627282930
31123456
 
RSS
創用 CC 授權條款
【廣告】
twMVC

Tags 分類檢視
關於作者

一個醉心技術又酷愛分享的Coding魔人,十年的IT職場生涯,寫過系統、管過專案, 也帶過團隊,最後還是無怨無悔地選擇了技術鑽研這條路,近年來則以做一個"有為的中年人"自許。

文章典藏
其他功能

這個部落格


Syndication