Какие символы двойных кавычек автоматически заменяются при преобразовании из UTF-8 в ISO-8859-15?

У меня есть входной файл в кодировке UTF-8. Мне нужно использовать часть его содержимого и создать из него CSV-файл в кодировке ISO-8859-15.

Проблема в том, что в UTF-8 есть несколько символов для двойных кавычек, которые автоматически заменяются символом " (= Кавычка U+0022) при записи CSV-файла на диск.

Те, что мы нашли, это:

Преобразование происходит автоматически, когда я пишу в файл 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 не удается.

Итак, вопрос:

Какие другие символы UTF-8 автоматически заменяются/преобразовываются в «обычный» символ " при преобразовании в ISO-8859-15? Это где-то задокументировано? Или я что-то не так здесь делаю?


person Krisztián Balla    schedule 02.12.2015    source источник
comment
Ради интереса, что вы ожидаете в этой ситуации? Я предполагаю, что ISO-8859-15 просто не включает эти символы.   -  person Jon Skeet    schedule 02.12.2015
comment
Ну, мне нравится, что они заменены таким образом. Но мне нужно знать, какие символы автоматически обрабатываются таким образом.   -  person Krisztián Balla    schedule 02.12.2015
comment
Похоже, вам следует просто преобразовать исходный контент в ISO-8859-15 как можно раньше, чтобы преобразование произошло до экранирования. Решит ли это проблему, не прибегая к исчерпывающим сведениям о заменах? Вы можете наивно найти хороший кусок замен, просто преобразовав строку с каждым символом Unicode в... но я не знаю, может ли кодировщик быть очень умным с несколькими символами в некоторых случаях..   -  person Jon Skeet    schedule 02.12.2015


Ответы (2)


Чтобы ответить на ваш вопрос, вот список кодовых точек Unicode, которые .NET сопоставляет с U + 0022 (то, что вы назвали «нормальным символом двойной кавычки») при использовании StreamWriter, как вы сделали:

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

Используя этот ответ, я быстро написал что-то, что создает обратное сопоставление UTF-8 с ISO-8859-15 (лат. 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, чего я не ожидал.

person ardila    schedule 02.12.2015
comment
Было бы разумно использовать ISO-8859-1 в качестве запасного варианта для ISO-8859-15, поскольку ISO-8859-15 тот же, но символ международной валюты заменен символом евро (€). Я жду вашего обновленного ответа. Что такое codePoint в вашем коде? - person Krisztián Balla; 02.12.2015
comment
В вашем списке персонажей нет моего, верно? Я обновляю свой вопрос вашими записями. - person Krisztián Balla; 02.12.2015
comment
Похоже, наша лиса готова. Я добавил if (latin9String == "\"") { System.Console.WriteLine(codePoint.ToString("X")); } в ваш цикл, и он напечатал коды из моего вопроса/вашего ответа. - person Krisztián Balla; 03.12.2015

.NET Framework по умолчанию использует наилучшее сопоставление при преобразовании из Unicode в устаревшие кодировки символов, такие как ISO-8859-15. Это описано в Справочнике по Unicode для протоколов Windows в MSDN. Этот документ ссылается на загрузку под названием «Таблицы весов сортировки» из Центра загрузки Microsoft, которая включает в себя наиболее подходящие сопоставления для устаревших кодировок, поддерживаемых Windows (в файле «Windows Supported Code Page Data Files.zip», на момент это письмо).

person Peter O.    schedule 02.12.2015