【转自CSDN】深入 Microsoft.VisualBasic.Strings.StrConv 簡繁轉換

深入 Microsoft.VisualBasic.Strings.StrConv 簡繁轉換

昨天又遇到一個簡繁轉換的需求, 雖然這個問題以前已經處理過了, 但是以前是用自己建立的 b52gb 和 gb2b5 的對應表來完成這個需求(VB6 的話就用 StrConv 方法來達成), 在 .NET 環境中, Microsoft.VisualBasic.dll 裡也有提供 Strings.StrConv 方法, 而且用法和原來的 VB6 幾乎是如出一轍, 可是昨天在使用 StrConv 的時候卻意外發現了一些奇怪的現象, 特別深入研究了一下, 順便記錄下來!

先來觀察 Strings.StrConv 方法的簽名:

public static string StrConv(string str, VbStrConv Conversion, [OptionalDefaultParameterValue(0)] int LocaleID)

第三個參數和 MSDN 上的文件有點不同, 上面的簽名是從 Reflector 中摘出來的, 也是這篇文章要記錄的重點, 先來看一些範例:

    a1 = Strings.StrConv("书樂う?", VbStrConv.TraditionalChinese, 0x0404);    // a1 = "?樂??"
    a2 = Strings.StrConv("书樂う?", VbStrConv.SimplifiedChinese, 0x0404);     // a2 = "????"

    b1 = Strings.StrConv("书樂う?", VbStrConv.TraditionalChinese, 0x0804);    // b1 = "書樂う?"
    b2 = Strings.StrConv("书樂う?", VbStrConv.SimplifiedChinese, 0x0804);     // b2 = "书乐う?"

    c1 = Strings.StrConv("书樂う?", VbStrConv.TraditionalChinese, 0x0412);    // c1 = "?樂う?"
    c2 = Strings.StrConv("书樂う?", VbStrConv.SimplifiedChinese, 0x0412);     // c2 = "??う?"

    d1 = Strings.StrConv("书樂う?", VbStrConv.TraditionalChinese, 0x0009);    // d1 = "書樂う?"
    d2 = Strings.StrConv("书樂う?", VbStrConv.SimplifiedChinese, 0x0009);     // d2 = "书乐う?"

上面 8 個範例的第一個參數摻雜了簡中、繁中、日文和韓文, 第二個參數區分了轉簡體和轉繁體, 第三個參數是 localeID 的部分, 分別包含了 zh-TW (0x0404), zh-CN (0x0840), ko-KR (0x0412), en (0x0009), 讓我們來仔細觀察一下結果, 一切的玄機都在第三個 localeID 參數身上. 我們先假設第三個參數 localeID 是用來表示來源字串的字集, 所以如果這個假設成立的話..., 來看看結果:

  1. a1: 嗯, 一切如預期的結果, 第一步應該先將 "书樂う?" 轉成符合 zh-TW (0x0404) 的字集, 所以結果是 "?樂??", 然後再根據第二個參數 VbStrConv.TraditionalChinese 結果變成了 "?樂??", 正確!
  2. a2: 第一步同上, 然後再根據第二個參數 VbStrConv.SimplifiedChinese 結果應該要變成 "?乐??", 可是 a2 的結果卻得到了 "????", 不如預期!
  3. b1: 第一步應該先將 "书樂う?" 轉成符合 zh-CN 的字集, 所以結果是 "书樂う?", (簡體字集是有包含繁體形態 "樂" 這個字的), 第二個參數 VbStrConv.TraditionalChinese, 所以結果變成 "書樂う?", 正確!
  4. b2: 正確!
  5. c1: 韓文字集不太了解, 從結果推測韓文的漢字集如果沒有 "书" 這個字的話, 結果應該算是正確的!
  6. c2: 從 c1 的結果本來預期應該得到 "?乐う?", 可是結果卻是 "??う?", 不如預期!
  7. d1: 咦!!! 怎麼會這樣, 完全不如預期, 竟然得到如此漂亮的結果, 本來預期是 4 個 "?" 的!!!
  8. d2: 一樣得到令人搞不清楚為什麼美麗結果!!!

這到底是怎麼一回事? 是假設錯誤嗎? 可是還有什麼別的可能嗎? 為了解開這個謎團, 於是又祭出了殺手工具 "Reflector", 仔細觀察了 Microsoft.VisualBasic.dll 內的程式碼, 終於了解箇中奧秘!

先來看一下 StrConv 方法反向工程之後的一小部分程式碼(還沒到重點, 所以只節錄最後幾行),

再來追進 vbLCMapString 看一看, 也是看下半部就行了:

橘黃色是和 Encoding 相關的程式碼, 綠色和紅色底線的部分是 Win32 API 用來處理字碼轉換的函式, 綠色底線的函式有一個後綴字 A, 而且輸入的參數是 byte[], 而紅色底線部分的函式則沒有後綴字, 輸入的參數是 string.

看到這兒, 答案已經呼之欲出了, 之所以結果會不如預期都是因為 encoding.GetBytes() 和 encoding.GetString() 這兩個方法給弄砸的, 如果可以跳過它們直接叫用底下畫紅線的 UnsafeNativeMethods.LCMapString 的話, 就不會有那些討厭的問號產生了, 那要怎麼樣才能避過那段我們不想要的程式碼呢? 看一下那個底下有畫虛線的部分 "encoding.IsSingleByte", 嗯! 沒錯, 這就是為什麼 d1, d2 的結果這麼令人驚訝的原因了, 因為 en 的 Encoding 就是 SingleByte 所以會直接跳過 Unicode 和 MBCS 互轉的部分, 而直接進行 Unicode 的轉碼, 於是得到美麗的答案, 整個過程分析完畢!

雖然已經知道整個來龍去脈, 但是如果能再了解一下那個神奇的 Win32API: LCMapString 的話, 想必觀念又可以再更清楚一些. 所以我們再來看看 LCMapString 的重點吧! 嗯~~重點在哪兒咧? 以此篇文章的需求 "簡繁轉換" 來看的話, 只有第二個參數 dwMapFlags 值得我們注意, 打開 MSDN 的文件, 透過索引找到 LCMapString 的章節, 我們可以看到以下的內容,

針對 Windows NT 4.0 以後的作業系統, Microsoft 已經早就幫程式設計師們準備好了一個現成的系統函式來達成簡繁轉換的工作了(唉! 為什麼沒有早點知道!), 看你是要轉簡體 (LCMAP_SIMPLIFIED_CHINESE), 或是轉繁體 (LCMAP_TRADITIONAL_CHINESE), 只要給個參數, 一切就搞定了, 就是這麼簡單!

結論

如果您的需求和我一樣, 只是想把文字內容的簡繁部分轉換, 並不是想轉成 big5 或 gb, 整個輸出入都是 unicode, 而且也不想破壞其他非簡繁文字部分的話, 那麼結論就是照著本篇文章的一開始的 d1, d2 範例呼叫 VB 的 Strings.StrConv 帶上 0x0009 或是其他 SingleByte 字集的 localeID 當成第三個參數就可以啦!!!

如果不想引入 Microsoft.VisualBasic.dll (別問為什麼, 純屬個人偏好) 又想要做到相同的效果, 做法也很簡單, 請參考以下的範例程式碼!!!

public static class ChineseStringUtility
{
    internal const int LOCALE_SYSTEM_DEFAULT = 0x0800;
    internal const int LCMAP_SIMPLIFIED_CHINESE = 0x02000000;
    internal const int LCMAP_TRADITIONAL_CHINESE = 0x04000000;

    [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    internal static extern int LCMapString(int Locale, int dwMapFlags, string lpSrcStr, int cchSrc, [Out] string lpDestStr, int cchDest);

    public static string ToSimplified(string source)
    {
        String target = new String(‘ ‘, source.Length);
        int ret = LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_SIMPLIFIED_CHINESE, source, source.Length, target, source.Length);
        return target;
    }

    public static string ToTraditional(string source)
    {
        String target = new String(‘ ‘, source.Length);
        int ret = LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_TRADITIONAL_CHINESE, source, source.Length, target, source.Length);
        return target;
    }
}
时间: 2025-01-01 20:58:35

【转自CSDN】深入 Microsoft.VisualBasic.Strings.StrConv 簡繁轉換的相关文章

C 对Microsoft VisualBasic My对象兰台妙选【月儿原创】

C#对Microsoft.VisualBasic My对象兰台妙选 作者:清清月儿 主页:http://blog.csdn.net/21aspnet/           时间:2007.4.24  1.添加引用 2.引用Microsoft.VisualBasic 命名空间 3.所有的My对象应用皆出自以下类库,本文仅抛砖引玉,更多请大家看MSDN 4.应用-获取应用程序所在服务器信息 说明:要添加using Microsoft.VisualBasic.Devices;代码using Syste

Microsoft.VisualBasic.DateAndTime.Timer 与 DateTime.Now.TimeOfDay.TotalSeconds 相当

如题,示例如下: Console.WriteLine(DateTime.Now.TimeOfDay.TotalSeconds); Console.WriteLine(Microsoft.VisualBasic.DateAndTime.Timer.ToString()); //Console.WriteLine(dt.Hour * 60.0 * 60.0 + dt.Minute * 60.0 + dt.Second); //Console.WriteLine(dt.TimeOfDay);

"一个实用的却被忽略的命名空间:Microsoft.VisualBasic":

当你看到这个命名空间的时候,别因为是vb的东西就匆忙关掉网页,那将会是您的损失,此命名空间中的资源最初目的是为了简化vb.net开发而创建的,所以microsoft.visualbasic并不属于system命名空间,而是独立存在的.虽然是为了vb而建的,但并不妨碍我们在c#中使用它. microsoft.visualbasic命名空间的资源,可以帮助我们方便.快捷的实用一些常用的计算机软/硬件及网络资源,提高开发中的效率. 对于本地计算机资源的使用,我们可能会着重关注microsoft.vis

.net简繁体转换

记录下,免得用的时候到处找 方法一 /// <summary> /// 中文字符工具类 /// </summary> public static class ChineseStringUtility {     private const int LOCALE_SYSTEM_DEFAULT = 0x0800;     private const int LCMAP_SIMPLIFIED_CHINESE = 0x02000000;     private const int LCMA

C# 实现繁体字和简体字之间的转换

今天收到一个需求,将一组简体的汉字转换成繁体的汉字,刚开始有点茫然,后来在网上搜了一下思路,结果很少有涉及,终于我在看了MSDN后找到了如何解决,可能这方面对一些高程来说很Easy,但是除了高程还有很大一部分的初中程并不知道,所以我写这个只是提醒和帮助一下大家.下面分享下: 1. 想要实现这个程序的目的,我们就要先确定怎么去实现,是否会用到一些其他的类库,总之一句话,我们要先确定需求,然后根据需求去分析. 2. 言归正传,首先我们要引用Microsoft.VisualBasic这个类库 3. 其

VB6.0 和VB.NET 函数对比

VB6.0和VB.Net的对照表 VB6.0 VB.NET AddItem Object名.AddItem Object名.Items.Add ListBox1.Items.Add ComboBox1.Items.Add Abs 函数 System.Math.Abs 方法 API 函数关系 MicrosoftWin32和Microsoft .NET Framework API的对应 App.Path 等 1. System.Reflection.Assembly.GetExecutingAsse

VB6.0和VB.Net的函数等对照表

VB6.0和VB.Net的对照表 VB6.0 VB.NET AddItem Object名.AddItem Object名.Items.Add ListBox1.Items.Add ComboBox1.Items.Add Abs 函数 System.Math.Abs 方法 API 函数关系 MicrosoftWin32和Microsoft .NET Framework API的对应 App.Path 等 1. System.Reflection.Assembly.GetExecutingAsse

繁简字转换(C#)

1.首先引入: using Microsoft.VisualBasic; 2.转换方法: //繁体转简体 public static string Traditional2Simplified(string str) { return (Strings.StrConv(str, Microsoft.VisualBasic.VbStrConv.SimplifiedChinese, 0)); } //简体转繁体 public static string Simplified2Traditional(

C#简繁体转换

/// <summary>/// 字符串简体转繁体/// </summary>/// <param name="strSimple"></param>/// <returns></returns>public static string ToTraditionalChinese(string strSimple){ string strTraditional = Microsoft.VisualBasic.Stri