【问题标题】:Which double quote characters are automatically replaced when converting from UTF-8 to ISO-8859-15?从 UTF-8 转换为 ISO-8859-15 时会自动替换哪些双引号字符?
【发布时间】:2016-03-06 13:49:42
【问题描述】:

我有一个 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 字符会自动替换/转换为“正常”" 字符?这是在某处记录的吗?还是我在这里做错了什么?

【问题讨论】:

  • 出于兴趣,您期望在这种情况下会发生什么?我假设 ISO-8859-15 不包含这些字符。
  • 嗯,我喜欢它们被这样替换。但我需要知道哪些字符是这样“自动”处理的。
  • 听起来您应该尽早将原始内容转换为 ISO-8859-15,以便转换发生在 转义之前。这会解决它而不必详尽地替换替换吗?您可以通过将字符串中的每个 Unicode 字符转换为一个字符串来天真地找到大量替换......但我不知道在某些情况下编码器是否会非常聪明地处理多个字符......

标签: c# .net csv utf-8 iso-8859-15


【解决方案1】:

为了回答您的问题,以下是 .NET 在您使用 StreamWriter 时映射到 U+0022(您称之为“正常双引号”符号)的 Unicode 代码点列表。 :

  • U+0022
  • U+02BA
  • U+030E
  • 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 替换了更多的字符,这是我没想到的。

【讨论】:

  • 使用 ISO-8859-1 作为 ISO-8859-15 的后备是有意义的,因为 ISO-8859-15 是相同的,但国际货币符号被替换为欧元(€ ) 象征。我正在等待您的更新答案。您的代码中的 codePoint 是什么?
  • 你的角色列表不包括我的,对吧?我用你的条目更新我的问题。
  • @JennyO'Reilly 这并不完全正确。还有一些不同之处。见en.wikipedia.org/wiki/ISO/…。在链接的问题中,codePoint 是一个 int,表示 Unicode 字符代码点。 PS:我弄清楚这种转换发生在框架内部的哪个位置不会改变已经给出的字符列表作为你的问题的答案:)
  • 看起来我们的 lis 已经完成了。我在你的循环中添加了if (latin9String == "\"") { System.Console.WriteLine(codePoint.ToString("X")); },它打印了我的问题/你的答案中的代码。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 2012-06-30
    • 2011-12-15
    • 2014-08-29
    • 1970-01-01
    • 1970-01-01
    • 2014-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多