Страницы

Поиск по вопросам

пятница, 13 декабря 2019 г.

Как прочесть кракозябры “ЇаЁўҐв”?

#c_sharp #net #кодировка


Есть строка "ЇаЁўҐв", как ее прочесть? Т.е. ее надо конвертировать из одной кодировки
в другую, как это сделать на C#? 



Дополнение: отвечаю на вопрос для чего это нужно и где такие строки бывают?
Если взять старые флоппи диски, с файлами, созданными в прошлом веке в MS-DOS, то
названия файлов бывают примерно такими "ЇаЁўҐв.txt", если смотреть в Windows. 
    


Ответы

Ответ 1



Указать кодировку при чтении содержимого файла. Т.е. для чтения ("перекодирования" при чтении) из 866 достаточно лишь указать Encoding: File.WriteAllText(@"c:\temp\test.txt", "тест!", Encoding.GetEncoding(866)); var text = File.ReadAllText("test.txt", Encoding.GetEncoding(866)); Если же у вас возник специфический кейс, например, вы получили уже испорченный текст как строку - то достаточно просто сохранить его обратно в байты с указанием неправильной кодировки, и прочитать с указанием правильной: static void Main(string[] args) { string bad = "ЇаЁўҐв"; string good = Convert(bad, 1251, 866); } static string Convert(string source, int from, int to) { byte[] bytes = Encoding.GetEncoding(from).GetBytes(source); return Encoding.GetEncoding(to).GetString(bytes); } Правда, сработает это только в случае, если чтение байт в неправильной кодировке (по счастливому совпадению!) окажется обратимым. Ниже показан пример, когда это не так. По поводу "перекодировки": Вы пытаетесь починить последствия, а не саму проблему. Как возникает такая проблема: У вас есть старый файл, в кодировке 866. Вы читаете его в строку без указания кодировки. Система не находит BOM, и читает файл в кодировке Encoding.Default. Вы пытаетесь "перекодировать прочитанную строку". Пример: // создали старый файл с содержимым в 866 File.WriteAllText("test.txt", "тест!", Encoding.GetEncoding(866)); // Открыли без указания кодировки, увидели кракозяблы: Console.WriteLine(File.ReadAllText("test.txt")); Решение, которое вы пытаетесь применить - это "сконвертировать строку". Т.е. вы надеетесь что следующий код сработает: static void Main(string[] args) { // создали старый файл с содержимым в 866 File.WriteAllText(@"c:\temp\test.txt", "тест!", Encoding.GetEncoding(866)); // Открыли без указания кодировки, увидели кракозяблы: var text = File.ReadAllText("test.txt"); Console.WriteLine(text); text = Convert(text, 866, 1251); Console.WriteLine(text); } static string Convert(string source, int from, int to) { byte[] bytes = Encoding.UTF8.GetBytes(source); byte[] newBytes = Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding(from), bytes); string newStr = Encoding.GetEncoding(to).GetString(newBytes); return newStr; } В этом решении есть слабое место - оно предполагает, строки в .net - это просто эдакий набор байт. Т.е. неважно в каком виде строка прочитана - ее можно обратно сконвертировать в те же самые байты, из которых ее прочитали. На самом деле это не так. Пример выше - нерабочий. Если не угадать кодировку файла при чтении - его не получится записать назад. File.WriteAllText(@"c:\temp\test.txt", "тест!", Encoding.GetEncoding(866)); var text = File.ReadAllText("test.txt"); File.WriteAllText(@"test2.txt", text); Внезапно, этот код выдает два разных файла, хотя никакого "перекодирования" не было.

Ответ 2



string Convert(string source, int from, int to) { byte[] bytes = Encoding.UTF8.GetBytes(source); byte[] newBytes = Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding(from), bytes); string newStr = Encoding.GetEncoding(to).GetString(newBytes); return newStr; } Использование: string str = "Привет"; string result = Convert(str, 866, 1251); => ЇаЁўҐв string result2 = Convert(result, 1251, 866); => Привет

Ответ 3



Есть строка "ЇаЁўҐв". Каким образом ее прочесть? Ваш 'привет'. 1251 и 866 обе однобайтные, поддерживают кириллицу и покрывают кодовый диапазон без потерь при неверной интерпретации (866-1251, 1251-866). Если требуется только прочесть, то не нужно ничего конвертировать. Достаточно выбрать верную кодовую страницу для интерпретации текста, (как было отмечено коллегами ранее - у Вас cp866) и задать ее при чтении массива байт или из потока. Варианты перечислены выше. Вот только не Сonvert, а то получите тоже самое, так-как Convert производит сопоставление, а не замену символов.

Комментариев нет:

Отправить комментарий