从UTF-8转换为ISO-8859-15时会自动替换哪些双引号字符?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从UTF-8转换为ISO-8859-15时会自动替换哪些双引号字符?相关的知识,希望对你有一定的参考价值。

我有一个UTF-8编码的输入文件。我需要使用它的一些内容并从中创建一个ISO-8859-15编码的CSV文件。

问题是UTF-8似乎有双引号的几个字符,在将CSV文件写入光盘时会自动替换为字符"(= Quotation Mark U+0022)。

我们发现的是:

当我写入CSV文件时,转换会自动发生,如下所示:

using (StreamWriter sw = new StreamWriter(workDir + "/files/vehicles.csv", append: false, encoding: Encoding.GetEncoding("ISO-8859-15")))
{
    foreach (ad vehicle in vehicles)
    {
        sw.WriteLine(convertVehicleToCsv(vehicle));
    }
}

方法convertVehicleToCsv转义双引号和数据的其他特殊字符,但不会转义特殊的UTF-8双引号字符。既然双引号被自动替换,则CSV不再符合RFC-4180,因此会损坏。使用我们的CSV库读取它失败。

所以问题是:

转换为ISO-8859-15时,其他哪些UTF-8字符会自动替换/转换为“普通”"字符?这是在某处记录的吗?或者我在这里做错了什么?

答案

要回答你的问题,这里是当你使用StreamWriter时,.NET将映射到U + 0022(你所谓的“普通双引号”符号)的Unicode代码点列表:

  • U + 0022
  • U + 02BA
  • U + 030EE
  • U + 201C
  • U + 201D
  • U + 201E
  • U + FF02

使用this answer,我快速写了一些东西,创建了UTF-8到ISO-8859-15(Latin-9)的反向映射。

Encoding utf8 = Encoding.UTF8;
Encoding latin9 = Encoding.GetEncoding("ISO-8859-15");
Encoding iso = Encoding.GetEncoding(1252);

var map = new Dictionary<string, List<string>>();

// same code to get each line from the file as per the linked answer

while (true)
{
    string line = reader.ReadLine();
    if (line == null) break;
    string codePointHexAsString = line.Substring(0, line.IndexOf(";"));
    int codePoint = Convert.ToInt32(codePointHexAsString, 16);

    // skip Unicode surrogate area
    if (codePoint >= 0xD800 && codePoint <= 0xDFFF)
        continue;

    string utf16String = char.ConvertFromUtf32(codePoint);
    byte[] utf8Bytes = utf8.GetBytes(utf16String);
    byte[] latin9Bytes = Encoding.Convert(utf8, latin9, utf8Bytes);
    string latin9String = latin9.GetString(latin9Bytes);
    byte[] isoBytes = Encoding.Convert(utf8, iso, utf8Bytes);
    string isoString = iso.GetString(isoBytes); // this is not always the same as latin9String!

   string latin9HexAsString = latin9[0].ToString("X");

    if (!map.ContainsKey(latin9HexAsString))
    {
        isoMap[latin9HexAsString] = new List<string>();
    }
    isoMap[latin9HexAsString].Add(codePointHexAsString);
}

有趣的是,ISO-8859-15似乎正在取代比ISO-8859-1更多的字符,这很有趣。一旦我有时间来测试这到底在哪里,我会更新我的答案以澄清这一点。

另一答案

在从Unicode转换为传统字符编码(例如ISO-8859-15)时,.NET Framework默认使用best-fit mapping。这在MSDN上的Windows Protocols Unicode Reference中有记录。该文档引用了Microsoft下载中心的名为“排序权重表”的下载,其中包括Windows支持的旧版编码的最佳匹配(在“Windows支持的代码页数据文件.zip”文件中,当时这篇文章)。

以上是关于从UTF-8转换为ISO-8859-15时会自动替换哪些双引号字符?的主要内容,如果未能解决你的问题,请参考以下文章

正确回显数组 ISO-8859-1 值

IPC::Open3 转换字符编码

FreeMarker 特殊字符输出为问号

Ubuntu解决中文乱码

获取charset字符串的编码器/解码器

php识别中文编码并自动转换为UTF-8