2013年9月11日 星期三

[轉貼] C# 繁簡轉換效能大車拚


出處:
C# 繁簡轉換效能大車拚  http://jian-zhoung.blogspot.tw/2012/07/c.html

C#使用LCMapString API函數進行中文簡繁體互相轉換  http://www.csframework.com/archive/2/arc-2-20110816-1794.htm
就目前已知在.Net平台上繁簡互轉的作法大約有四種
1. Microsoft.VisualBasic.dll
    .Net平台內建可以直接參考使用,效率三級。               
2. Microsoft Visual Studio International Pack 1.0 SR1
    微軟官方所出的官方套件,需要另外安裝,目前不支援 VS 2008 以上的版本,官方網站下載後無法在VS 2008 以上的版本安裝,需要另外在網路上尋找 ChineseConverter.dll 加入參考,效率二級。              
3. Microsoft.Office.Interop.Word.dll(Office 2010 Ver.14.0.4762.1000)
    系統上若裝了 Office 就有,唯一提供繁簡詞意互轉的套件,但是轉換效能就不那麼漂亮,效率五級。              
4. OS Kernel LCMapString
    什麼都不用裝,直接使用系統內核kernel32.dll 提供的LCMapString 來進行轉換,效率一級。
測試結果數據如下︰
VisualBasic Convert︰15.9458 ms
Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter︰3.5011 ms      
Microsoft.Office.Interop.Word︰10082.5081 ms
Kernel32 LCMapString︰1.5212 ms

相關的程式碼︰
///
/// 使用系統 kernel32.dll 進行轉換
///
private const int LocaleSystemDefault = 0x0800;
private const int LcmapSimplifiedChinese = 0x02000000;
private const int LcmapTraditionalChinese = 0x04000000;

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

public static string ToSimplified(string argSource)
{
    var t = new String(' ', argSource.Length);
    LCMapString(LocaleSystemDefault, LcmapSimplifiedChinese, argSource, argSource.Length, t, argSource.Length);
    return t;
}

public static string ToTraditional(string argSource)
{
    var t = new String(' ', argSource.Length);
    LCMapString(LocaleSystemDefault, LcmapTraditionalChinese, argSource, argSource.Length, t, argSource.Length);
    return t;
}

///
/// 使用 Office Word (Microsoft.Office.Interop.Word) 進行轉換
///
public static string ConvertUsingWord(string argSource, bool argIsCht)
{
    var doc = new Document();
    doc.Content.Text = argSource;
    doc.Content.TCSCConverter(
        argIsCht
            ? WdTCSCConverterDirection.wdTCSCConverterDirectionTCSC
            : WdTCSCConverterDirection.wdTCSCConverterDirectionSCTC, true, true);
    var ret = doc.Content.Text;
    object saveChanges = false;
    object originalFormat = Missing.Value;
    object routeDocument = Missing.Value;
    doc.Close(ref saveChanges, ref originalFormat, ref routeDocument);
    return ret;
}

測式碼︰
public void RunTest()
{  
    var i = 1000;
    var sw = new System.Diagnostics.Stopwatch();
    sw.Reset();
    sw.Start();
    while (--i > 0)
    {
        Strings.StrConv("她來聽我 的演唱會 在十七歲的初戀 第一次約會,繁轉簡
", VbStrConv.SimplifiedChinese, 2052);
        Strings.StrConv("她U+6765听我 的演唱U+4F1A 在十七U+5C81的初U+604B 第一次U+7EA6U+4F1A,簡轉繁
", VbStrConv.TraditionalChinese, 2052);
    }

    sw.Stop();
    Response.Write(string.Format("
VisualBasic Convert︰{0}
",
                                 sw.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture)));
    i = 1000;
    sw.Reset();
    sw.Start();
    while (--i > 0)
    {
        ChineseConverter.Convert("她來聽我 的演唱會 在十七歲的初戀 第一次約會,繁轉簡
",
                                 ChineseConversionDirection.TraditionalToSimplified);
        ChineseConverter.Convert("她U+6765听我 的演唱U+4F1A 在十七U+5C81的初U+604B 第一次U+7EA6U+4F1A,簡轉繁
",
                                 ChineseConversionDirection.SimplifiedToTraditional);
    }
    sw.Stop();
    Response.Write(
        string.Format(
            "
Microsoft.International.Converters.TraditionalChineseToSimplifiedConverter︰{0}
",
            sw.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture)));

    i = 100;
    sw.Reset();
    sw.Start();
    while (--i > 0)
    {

        ConvertUsingWord("她來聽我 的演唱會 在十七歲的初戀 第一次約會,繁轉簡
", true);
        ConvertUsingWord("她U+6765听我 的演唱U+4F1A 在十七U+5C81的初U+604B 第一次U+7EA6U+4F1A,簡轉繁
", false);
    }
    sw.Stop();
    Response.Write(string.Format("
Microsoft.Office.Interop.Word︰{0}
",
                                 sw.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture)));
    i = 1000;
    sw.Reset();
    sw.Start();
    while (--i > 0)
    {

        ToSimplified("她來聽我 的演唱會 在十七歲的初戀 第一次約會,繁轉簡
");
        ToTraditional("她U+6765听我 的演唱U+4F1A 在十七U+5C81的初U+604B 第一次U+7EA6U+4F1A,簡轉繁
");
    }
    sw.Stop();
    Response.Write(string.Format("
kernel32 LCMapString︰{0}
",
                                 sw.Elapsed.TotalMilliseconds.ToString(CultureInfo.InvariantCulture)));
}

==============================================================

簡體中文 (Simplified Chinese)和繁體中文(傳統漢字,Traditional Chinese)之間的轉換,單純使用字字對照轉換是絕對無法準確的。所以,在使用下面的方法進行了 C# 簡繁轉換後,務必對轉換結果進行修正,才能保證可以使用。
修正主要包括:
1、一對多關係時根據詞義換用字;
2、兩岸(或港台和內地)詞彙差異,如「網上鄰居」和「網絡上的芳鄰」、「最終用戶許可協議」和「最終用戶許可協議」。
C# Code:

/// <summary>
/// C#使用LCMapString API函數進行中文簡繁體互相轉換
/// </summary>
public static class ChineseConverter
{
   internal const int LOCALE_SYSTEM_DEFAULT = 0x0800;
   internal const int LCMAP_SIMPLIFIED_CHINESE = 0x02000000;
   internal const int LCMAP_TRADITIONAL_CHINESE = 0x04000000;
  
   /// <summary> 
   /// 使用OS的kernel.dll做為簡繁轉換工具,只要有裝OS就可以使用,不用額外引用dll,但只能做逐字轉換,無法進行詞意的轉換 
   /// <para>所以無法將電腦轉成計算機</para> 
   /// </summary> 
   [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);
  
   /// <summary> 
   /// 繁體轉簡體 
   /// </summary> 
   /// <param name="pSource">要轉換的繁體字:體</param> 
   /// <returns>轉換後的簡體字:體</returns> 
   public static string ToSimplified(string pSource)
   {
      String tTarget = new String(' ', pSource.Length);
      int tReturn = LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_SIMPLIFIED_CHINESE, pSource, pSource.Length, tTarget, pSource.Length);
      return tTarget;
   }
  
   /// <summary> 
   /// 簡體轉繁體 
   /// </summary> 
   /// <param name="pSource">要轉換的繁體字:體</param> 
   /// <returns>轉換後的簡體字:體</returns> 
   public static string ToTraditional(string pSource)
   {
      String tTarget = new String(' ', pSource.Length);
      int tReturn = LCMapString(LOCALE_SYSTEM_DEFAULT, LCMAP_TRADITIONAL_CHINESE, pSource, pSource.Length, tTarget, pSource.Length);
      return tTarget;
   }
   

沒有留言:

張貼留言