C#UNICODE到ANSI转换

时间:2013-06-10 11:54:45

标签: c# unicode ansi

在.NET Framework中使用UNICODE编码时,我需要你帮助解决一些令我不安的事情......

我必须使用非UNICODE应用程序与某些客户数据系统连接,这些客户拥有全球公司(中文,韩文,俄文......)。所以他们必须为我提供一个ASCII 8位文件,它将用他们的Windows代码页进行编码。

因此,如果希腊客户在产品名称中向我发送包含'Σ'(sigma字母'\ u03A3')的文本文件,我将获得与211 ANSI代码点对应的等效字母,在我自己的代码中表示页。我的电脑是法语Windows,这意味着代码页是Windows-1252,所以我会在这个文本文件中使用'Ó'......好的。

我知道这个客户是希腊客户,因此我可以通过在导入参数中强制使用windows-1253代码页来阅读他的文件。

/// <summary>
/// Convert a string ASCII value using code page encoding to Unicode encoding
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public static string ToUnicode(string value, int codePage)
{
    Encoding windows = Encoding.Default;
    Encoding unicode = Encoding.Unicode;
    Encoding sp = Encoding.GetEncoding(codePage);
    if (sp != null && !String.IsNullOrEmpty(value))
    {
        // First get bytes in windows encoding
        byte[] wbytes = windows.GetBytes(value);

        // Check if CodePage to use is different from current Windows one
        if (windows.CodePage != sp.CodePage)
        {
            // Convert to Unicode using SP code page
            byte[] ubytes = Encoding.Convert(sp, unicode, wbytes);
            return unicode.GetString(ubytes);
        }
        else
        {
            // Directly convert to Unicode using windows code page
            byte[] ubytes = Encoding.Convert(windows, unicode, wbytes);
            return unicode.GetString(ubytes);
        }
    }
    else
    {
        return value;
    }
}

最后我在我的应用程序中得到了'Σ',我可以将其保存到我的SQL Server数据库中。现在我的应用程序必须执行一些复杂的计算,然后我必须通过自动导出将此文件交还给客户...

所以我的问题是我必须执行UNICODE =&gt; ANSI转换?!但这并不像我在开始时想的那么简单......

我不想保存导入期间使用的代码页,所以我的第一个想法是将UNICODE转换为windows-1252,然后自动将文件发送给客户。他们将使用自己的代码页读取导出的文本文件,因此这个想法对我来说很有意思。

但问题是这种转换有一种奇怪的行为......这里有两个不同的例子:

第一个例子(я)

char ya = '\u042F';
string strYa = Char.ConvertFromUtf32(ya);
System.Text.Encoding unicode = System.Text.Encoding.Unicode;
System.Text.Encoding ansi1252 = System.Text.Encoding.GetEncoding(1252);
System.Text.Encoding ansi1251 = System.Text.Encoding.GetEncoding(1251);

string strYa1252 = ansi1252.GetString(System.Text.Encoding.Convert(unicode, ansi1252, unicode.GetBytes(strYa)));
string strYa1251 = ansi1251.GetString(System.Text.Encoding.Convert(unicode, ansi1251, unicode.GetBytes(strYa)));

所以 strYa1252 包含'',而 strYa1251 包含有效字符'я'。因此,如果没有向Convert()函数指示有效的代码页,那么似乎不可能转换为ANSI ...因此Unicode Encoding类中的任何内容都不能帮助用户获得ANSI和UNICODE代码点之间的等价? :\

第二个例子(Σ)

char sigma = '\u3A3';
string strSigma = Char.ConvertFromUtf32(sigma);
System.Text.Encoding unicode = System.Text.Encoding.Unicode;
System.Text.Encoding ansi1252 = System.Text.Encoding.GetEncoding(1252);
System.Text.Encoding ansi1253 = System.Text.Encoding.GetEncoding(1253);

string strSigma1252 = ansi1252.GetString(System.Text.Encoding.Convert(unicode, ansi1252, unicode.GetBytes(strSigma)));
string strSigma1253 = ansi1253.GetString(System.Text.Encoding.Convert(unicode, ansi1253, unicode.GetBytes(strSigma)));

目前,我在 strSigma1253 字符串中输入了正确的“Σ”,但 S > strSigma1252 即可。如开头所示,如果找到ANSI代码,我应该'Ó',或'?'如果找不到角色,但不是'S'。为什么? 是的,当然,语言学家可以说'S'相当于希腊的Sigma字符,因为它们在两个字母表中听起来都一样,但它们没有相同的ANSI代码!

那么.NET框架中的Convert()函数如何管理这种等价?

有人有想法在我必须发送给客户的文本文件中写回UNICODE的ANSI字符吗?

1 个答案:

答案 0 :(得分:6)

  

我应该......'?'如果找不到角色,但不是'S'。为什么呢?

这被称为“最适合”编码,在大多数情况下,这是一件坏事。当Windows无法将字符编码到目标代码页时(因为代码页1252中不存在Σ),它会尽最大努力将字符映射到类似的东西。这可能意味着丢失变音标记(ëe),或映射到同源(ΣS),这是一个相关的字符(=),一个不相关但看起来有点类似的角色(8),或者其他任何疯狂的替代品在当时看起来都是个好主意,但结果却是文化上的或在实践中数学上令人反感。

您可以查看cp1252的表格,包括Sigma映射,here

除了无声的有用之外,还有一些quite bad security implications。您应该可以通过将EncoderFallback设置为ReplacementFallbackExceptionFallback来阻止它发生。

  

是否有人有想法在我必须发送给客户的文本文件中写回UNICODE的ANSI字符?

您必须为每位客户保留一份编码表。使用该编码读取其输入文件进行解码;使用相同的编码写出他们的输出文件。

(为了理智,将新客户设置为UTF-8并记录这是首选编码。)