从 UTF-8 转换为 ISO-8859-15 时,哪些双引号字符会自动替换?
Which double quote characters are automatically replaced when converting from UTF-8 to ISO-8859-15?
我有一个 UTF-8 编码的输入文件。我需要使用它的一些内容并从中创建一个 ISO-8859-15 编码的 CSV 文件。
问题是 UTF-8 似乎有几个双引号字符在将 CSV 文件写入光盘时自动替换为字符 "
(= Quotation Mark U+0022)。
我们找到的是:
- Left Double Quotation Mark U+201C
- Right Double Quotation Mark U+201D
- Double Low-9 Quotation Mark U+201E
- Modifier Letter Double Prime U+02BA
- Combining Double Vertical Line Above U+030E
- Fullwidth Quotation Mark U+FF02
当我像这样写入 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 字符会自动 replaced/converted 为“普通”"
字符?这在某处记录了吗?还是我做错了什么?
为了回答您的问题,这里是 .NET 在使用 StreamWriter
作为你已经完成了:
- 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 更多的字符,这是我没想到的。
.NET Framework 在 MSDN 上使用 best-fit mapping by default when converting from Unicode to legacy character encodings, such as ISO-8859-15. This is documented in the Windows Protocols Unicode Reference。该文档引用了来自 Microsoft 下载中心的名为 "Sorting Weight Tables" 的下载,其中包括 Windows 支持的旧编码的最佳映射(在文件 "Windows Supported Code Page Data Files.zip" 中,在本文发布时写作)。
我有一个 UTF-8 编码的输入文件。我需要使用它的一些内容并从中创建一个 ISO-8859-15 编码的 CSV 文件。
问题是 UTF-8 似乎有几个双引号字符在将 CSV 文件写入光盘时自动替换为字符 "
(= Quotation Mark U+0022)。
我们找到的是:
- Left Double Quotation Mark U+201C
- Right Double Quotation Mark U+201D
- Double Low-9 Quotation Mark U+201E
- Modifier Letter Double Prime U+02BA
- Combining Double Vertical Line Above U+030E
- Fullwidth Quotation Mark U+FF02
当我像这样写入 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 字符会自动 replaced/converted 为“普通”"
字符?这在某处记录了吗?还是我做错了什么?
为了回答您的问题,这里是 .NET 在使用 StreamWriter
作为你已经完成了:
- 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 更多的字符,这是我没想到的。
.NET Framework 在 MSDN 上使用 best-fit mapping by default when converting from Unicode to legacy character encodings, such as ISO-8859-15. This is documented in the Windows Protocols Unicode Reference。该文档引用了来自 Microsoft 下载中心的名为 "Sorting Weight Tables" 的下载,其中包括 Windows 支持的旧编码的最佳映射(在文件 "Windows Supported Code Page Data Files.zip" 中,在本文发布时写作)。