Big5-HKSCS編碼初探(下)

昨天介紹了Big5-HKSCS,初步心得是: Big5-HKSCS跟Big5一樣是歷史的眼淚,新一代Unicode標準已能涵蓋其字元範圍又能同時兼容各國語系。因此,拋棄ANSI規格,回歸Unicode才是王道!!

但這衍生一個需求 -- 若既存文字檔或其他老系統仍採用Big5-HKSCS編碼內容,是否能用.NET程式轉換為Unicode呢?

拿這種問題來問傳說中偉大的中文編碼解碼工具程式作者,是一種羞辱吧? 只見那個其貌不揚的中年男子,右手收在腰後,不屑地伸出左手在鍵盤上飛快地敲了一段程式:

File.ReadAllText("d:\\hkscs-test.htm", Encoding.GetEncoding(951));

接著用鄙夷的口吻說道: "Encoding.GetEncoding(950)解析Big5的寫法都示範過幾百遍,Big5-HKSCS的CodePage是951,照著用Encdoing.GetEncoding(951)不就好了? 這也要問? 笨!!"

實測程式。哐噹! 不知哪裡飛來一塊鐵板,砸在剛才還盛氣凌人的中年男子頭上...

.NET賞了一個NotSupportedException: {"No data is available for encoding 951."} !!

查了MSDN討論區文章,發現一件殘酷的事實 -- Vista之後,Windows已經不再提供HKSCS編碼語言包了!

Starting with Windows Vista, HKSCS-2004 characters are only be supported as Unicode 4.1 or later. All characters are assigned standard, non-PUA codepoints. The characters are displayed with the MingLiU font, and these characters can be entered via the keyboard. The patch that provides Big5 encoding of HKSCS is unsupported in Windows Vista and later. A utility provided by Microsoft is available to convert HKSCS and Unicode PUA-encoded characters to Unicode 4.1 version. 951版本中的Big5編碼字在Vista之後的版本是不兼容的。在Windows XP之前的版本,你可以安裝語言包支持它。

所幸,文中提到微軟有個轉換工具能將HKSCS轉成Unicode。找到一個程式庫 -- Microsoft Character Code Conversion Routines For HKSCS-2004,它是個Unmanaged Library(hkscs04.dll),只有C++範例,而我只會寫C#,得透過DllImport外部函式庫的方式呼叫它。

可能因為涉及字串內容語系轉換,我發現先前在其他PInvoke函式用StringBuilder接收結果字串的技巧不管用,只好胡亂試些繞道做法。最後,C/C++麻瓜花了點時間試出用IntPtr當成結果字串參數、用Marshal.AllocHGlobal()取得記憶體空間、再用Marshal.Copy()將內容搬至byte[]的做法,總算順利取回轉換結果。最後,再把邏輯包成string Convert(string) .NET方法方便使用。

using System;
using System.Runtime.InteropServices;
using System.Text;
 
class HkscsHelper
{
    const uint HKSCS_ERR_INVALID_CHARS = 0x00000001;
 
    [DllImport("hkscs04.dll", CharSet = CharSet.Ansi, SetLastError = true)]
    public static extern int HKSCS_Big5ToUnicode41(
        uint dwFlags, string lpBig5Str, int cbBig5,
        IntPtr lpUnicode41Str, int cchUnicode41);
 
    public static string Convert(string srcString)
    {
        int srcLen = Encoding.GetEncoding(950).GetByteCount(srcString);
        int len = HKSCS_Big5ToUnicode41(HKSCS_ERR_INVALID_CHARS, 
                  srcString, srcLen, IntPtr.Zero, 0);
        IntPtr ipDst = Marshal.AllocHGlobal(len);
        try
        {
            int resLen = 2 * HKSCS_Big5ToUnicode41(HKSCS_ERR_INVALID_CHARS, 
                             srcString, srcLen, ipDst, len);
            byte[] dst = new byte[resLen];
            Marshal.Copy(ipDst, dst, 0, resLen);
            return Encoding.Unicode.GetString(dst);
        }
        finally
        {
            Marshal.FreeHGlobal(ipDst);
        }
    }
}

用前篇文章的"滙豐銀行 警衞室"來驗證看看,成功!!

聲明: 我整合Unmanaged Library的經驗有限,不確定文中採用的做法是否夠嚴謹有效率,尚請高手前輩們不吝指正。

歡迎推文分享:
Published 28 February 2014 07:08 AM 由 Jeffrey
Filed under:
Views: 12,990



意見

# CIHsieh said on 01 March, 2014 08:22 AM

另一種方式, 供參考:

static string Convert(string str)

{

   try

   {

       var strLen = Encoding.GetEncoding(950).GetByteCount(str);

       var sb = new StringBuilder();

       var len = (int)HKSCS_Big5ToUnicode41(HKSCS_ERR_INVALID_CHARS, str, strLen, sb, 0);

       HKSCS_Big5ToUnicode41(HKSCS_ERR_INVALID_CHARS, str, strLen, sb, len);

       return sb.ToString();

   }

   catch (Exception ex)

   {

       Console.WriteLine(ex);

       return "ERR";

   }

}

public const int HKSCS_ERR_INVALID_CHARS = 1;

[DllImport("hkscs04.dll",

   EntryPoint = "HKSCS_Big5ToUnicode41",

   CallingConvention = CallingConvention.StdCall)]

public static extern uint HKSCS_Big5ToUnicode41(

   uint dwFlags,

   [In] [MarshalAs(UnmanagedType.LPStr)] string lpBig5Str,

   int cbBig5,

   [Out] [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpUnicode41Str,

   int cchUnicode41);

# Jeffrey said on 02 March, 2014 05:47 AM

to CIHsieh, 感謝指點(用力筆記),回歸StringBuilder簡潔多了。

# rick said on 03 March, 2014 08:26 PM

試一下包字型,網頁也是會顯示的

細明體_HKSCS

# Jeffrey said on 04 March, 2014 03:22 AM

to rick, 好主意! 用HK專屬字型也是種解法,謝謝補充!

# Rudolf said on 19 March, 2014 10:39 AM

有把 Unicode 字 對應 Big-5 HKSCS 的方法嗎?

Windows 7 倉頡 / 速成 只能打 Unicode 的香港字, 但本人仍在使用 ANSI 的軟件,需要打Big5 的香港字...

又或者有沒有輸入 Unicode 香港字 找到對應 的 Big5 內碼的方法?

# Jeffrey said on 19 March, 2014 08:45 PM

to Rudolf, 這個對照表(charset.uic.jp/.../bold)或許能幫上忙。

# Victor said on 25 April, 2018 05:07 AM

想問下重有無save到

hkscs04.dll

?

Thanks

你的看法呢?

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

5 + 3 =

搜尋

Go

<February 2014>
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
2324252627281
2345678
 
RSS
創用 CC 授權條款
【廣告】
twMVC
最新回應

Tags 分類檢視
關於作者

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

文章典藏
其他功能

這個部落格


Syndication