2

我的目标是将 .NET 字符串 (Unicode) 转换为 Windows-1252,并在必要时将原始 UTF-8 字符串存储在 Base64 实体中。

例如,转换为 1252 的字符串“DJ Doena”仍然是“DJ Doena”。

但是,如果您将树(木)的日语汉字转换为 1251,您最终会得到一个问号。

这些是我的测试字符串:

String doena = "DJ Doena";
String umlaut = "äöüßéèâ";
String allIn = "< ä ß á â & 木 >";

这就是我首先转换字符串的方式:

using (MemoryStream ms = new MemoryStream())
{
    using (StreamWriter sw = new StreamWriter(ms, Encoding.UTF8))
    {
        sw.Write(decoded);
        sw.Flush();
        ms.Seek(0, SeekOrigin.Begin);
        using (StreamReader sr = new StreamReader(ms, Encoding.GetEncoding(1252)))
        {
            encoded = sr.ReadToEnd();
        }
    }
}

问题是,虽然调试字符串比较声称两者确实是相同的,所以一个简单的==or.Equals()是不够的。

这就是我尝试找出是否需要 base64 并生成它的方法:

private static String GetBase64Alternate(String utf8Text, String windows1252Text)
{
    Byte[] utf8Bytes;
    Byte[] windows1252Bytes;
    String base64;

    utf8Bytes = Encoding.UTF8.GetBytes(utf8Text);
    windows1252Bytes = Encoding.GetEncoding(1252).GetBytes(windows1252Text);
    base64 = null;
    if (utf8Bytes.Length != windows1252Bytes.Length)
    {
        base64 = Convert.ToBase64String(utf8Bytes);
    }
    else
    {
        for(Int32 i = 0; i < utf8Bytes.Length; i++)
        {
            if(utf8Bytes[i] != windows1252Bytes[i])
            {
                base64 = Convert.ToBase64String(utf8Bytes);
                break;
            }
        }
    }
    return (base64);
}

第一个字符串doena完全相同,不会产生 base64 结果

Console.WriteLine(String.Format("{0} / {1}", windows1252Text, base64Text));

结果是

DJ Doena /

但是第二个字符串umlauts在 UTF-8 中的字节数已经是 1252 中的两倍,因此即使看起来没有必要,它也会生成一个 Base64 字符串:

äöüßéèâ / w6TDtsO8w5/DqcOow6I=

第三个做了它应该做的事情(不再是“木”而是一个“?”,因此需要base64):

< ä ß á â & ? > / PCDDpCDDnyDDoSDDoiAmIOacqCA+

有什么线索可以增强我的 Base64 吸气剂 a) 性能 b) 以获得更好的结果吗?

先感谢您。:-)

4

2 回答 2

3

我不确定我是否完全理解了这个问题。但我试过了。:) 如果我理解正确,则此代码可以满足您的要求:

static void Main(string[] args)
{
    string[] testStrings = { "DJ Doena", "äöüßéèâ", "< ä ß á â & 木 >" };

    foreach (string text in testStrings)
    {
        Console.WriteLine(ReencodeText(text));
    }
}

private static string ReencodeText(string text)
{
    Encoding encoding = Encoding.GetEncoding(1252);
    string text1252 = encoding.GetString(encoding.GetBytes(text));

    return text.Equals(text1252, StringComparison.Ordinal) ?
        text : Convert.ToBase64String(Encoding.UTF8.GetBytes(text));
}

即,它将文本编码为 Windows-1252,然后解码回一个string对象,然后将其与原始对象进行比较。如果比较成功,则返回原始字符串,否则将其编码为 UTF8,然后编码为 base64。

它产生以下输出:

DJ Doena
äöüßéèâ
PCDDpCDDnyDDoSDDoiAmIOacqCA+

换句话说,前两个字符串保持不变,而第三个被编码为 base64。

于 2014-12-16T19:11:54.170 回答
1

在您的第一个代码中,您使用一种编码对字符串进行编码,然后使用不同的编码对其进行解码。那根本不会给您任何可靠的结果。这相当于用八进制写出一个数字,然后像读取十进制一样读取它。对于不超过 7 的数字,它似乎工作得很好,但在那之后你会得到无用的结果。

GetBase64Alternate方法的问题在于它将字符串编码为两种不同的编码,并且假设第一种编码不支持某些字符,如果第二种编码导致不同的字节集。

比较字节序列并不能告诉您是否有任何编码失败。如果失败,序列会有所不同,但如果在编码之间存在任何编码不同的字符,它也会有所不同。

您要做的是确定编码是否确实适用于所有字符。您可以通过Encoding为不受支持的字符创建一个具有后备功能的实例来做到这一点。你可以使用一个EncoderExceptionFallback类,EncoderFallbackException如果它被调用,它会抛出一个。

此代码将尝试在字符串上使用 Windows-1252 编码,并将ok变量设置为false如果编码不支持字符串中的所有字符:

Encoding e = Encoding.GetEncoding(1252, new EncoderExceptionFallback(), new DecoderExceptionFallback());
bool ok = true;
try {
  e.GetByteCount(allIn);
} catch (EncoderFallbackException) {
  ok = false;
}

由于您实际上不会将编码结果用于任何事情,因此您可以使用该GetByteCount方法。它将检查如何在不产生编码结果的情况下对所有字符进行编码。

在您的方法中使用它将是:

private static String GetBase64Alternate(string text) {
  Encoding e = Encoding.GetEncoding(1252, new EncoderExceptionFallback(), new DecoderExceptionFallback());
  bool ok = true;
  try {
    e.GetByteCount(allIn);
  } catch (EncoderFallbackException) {
    ok = false;
  }
  return ok ? null : Convert.ToBase64(Encoding.UTF8.GetBytes(text));
}
于 2014-12-16T19:43:55.207 回答