Основная проблема и вопрос:
При наличии искаженной строки, для которой известен фактический текст, возможно ли последовательно исправить искаженную строку?
СогласноNyerguds прокомментировал этот ответ :
Если строка является неправильным декодированием, выполненным просто 8-битным кодированием, и у вас есть кодировка, используемая для декодированияэто, вы можете обычно вернуть байты без какого-либо искажения.
(подчеркивает мое)
Что говорит о том, что бывают случаи, когда это не такможно получить исходные байты обратно.Это приводит меня к следующему вопросу: Существуют ли случаи, когда (неправильное) кодирование массива байтов является операцией с потерями и необратимой операцией?
Справочная информация: Я звонювнешняя библиотека C ++, которая где-то вызывает веб-API.Иногда эта библиотека дает мне слегка искаженный текст.В моем проекте на C # я пытаюсь найти способ последовательно обратить неправильное кодирование, но мне кажется, что я могу сделать это только часть времени.
Что я пробовал:
Кажется очевидным, что библиотека C ++ неправильно кодирует исходные байты, которые она позже передает мне в виде строки.Мой подход состоял в том, чтобы угадать кодировку, которую библиотека C ++ использовала для интерпретации исходных байтов источника.Затем я перебираю все возможные кодировки, переосмысливая, мы надеемся, «оригинальные» байты с другой кодировкой.
class TestCase
{
public string Original { get; set; }
public string Actual { get; set; }
public List<string> Matches { get;} = new List<string>();
}
void Main()
{
var testCases = new List<TestCase>()
{
new TestCase {Original = "窶弑-shaped", Actual = "“U-shaped"},
new TestCase {Original = "窶廡窶・Type", Actual = "“F” Type"},
new TestCase {Original = "Ko窶冩lau", Actual = "Ko’olau"},
new TestCase {Original = "窶彗s is", Actual = "“as is"},
new TestCase {Original = "窶從ew", Actual = "“new"},
new TestCase {Original = "faテァade", Actual = "façade"}
};
var encodings = Encoding.GetEncodings().Select(x => x.GetEncoding()).ToList();
foreach (var testCase in testCases)
{
foreach (var from in encodings)
{
foreach (var to in encodings)
{
// Guess the original bytes of the string
var guessedSourceBytes = from.GetBytes(testCase.Original);
// Guess what the bytes should have been interpreted as
var guessedActualString = to.GetString(guessedSourceBytes);
if (guessedActualString == testCase.Actual)
{
testCase.Matches.Add($"Reversed using \"{from.CodePage} {from.EncodingName}\", reinterpreted as: \"{to.CodePage} {to.EncodingName}\"");
}
}
}
}
}
Как мы видим выше,из шести тестовых случаев все, кроме одного (窶廡窶・
) были успешными.В успешных случаях Shift-JIS (кодовая страница 932), казалось, приводил к правильной «исходной» последовательности байтов для UTF8.
Получение байтов Shift-JIS для 窶廡窶・
приводит к: E2 80 9C 46 E2 80 81 45
.E2 80 9C
совпадает с байтами UTF8 для левой двойной кавычки , что является правильным.Однако E2 80 81
- это em quad
в UTF8, а не right double quotation mark
, который я ожидаю.Повторная интерпретация всей последовательности байтов в UTF8 приводит к “F EType
Независимо от того, какую кодировку я использую для получения «оригинальных» байтов, и независимо от того, какую кодировку я использую для переинтерпретации упомянутых байтов, кажется, что комбинация не можетчтобы успешно преобразовать 窶廡窶・
в “F”
.
Интересно, если я получу байты UTF8 для “F” Type
и намеренно неверно интерпретирую эти байты как Shift-JIS, я получу обратно 窶廡窶・Type
Encoding.GetEncoding(932).GetString(Encoding.UTF8.GetBytes("“F” Type"))
Это наводит меня на мысль, что кодировка может на самом деле привести к потере данных.Я не очень хорошо разбираюсь в кодировке, поэтому кто-то может подтвердить, правильно ли сделан мой вывод, и если да, то почему происходит потеря данных?