C # Преобразование строки из UTF-8 в ISO-8859-1 (Latin1) H

Я погуглил по этой теме и просмотрел все ответы, но до сих пор не понимаю.

В основном мне нужно преобразовать строку UTF-8 в ISO-8859-1, и я делаю это, используя следующий код:

Encoding iso = Encoding.GetEncoding("ISO-8859-1");
Encoding utf8 = Encoding.UTF8;
string msg = iso.GetString(utf8.GetBytes(Message));

Моя исходная строка

Message = "ÄäÖöÕõÜü"

Но, к сожалению, моя строка результата становится

msg = "�ä�ö�õ�ü

Что я здесь делаю не так?


person Daniil Harik    schedule 17.12.2009    source источник
comment
Все строки в .NET внутренне хранят строки с использованием символов Юникода. Нет понятия, что строка является windows-1252, iso-8859-1, utf-8 и т. Д. Вы пытаетесь выбросить какие-либо символы в вашей строке, которые не представлены на кодовой странице Windows-1252?   -  person Ian Boyd    schedule 17.12.2009
comment
@IanBoyd На самом деле, String - это подсчитанная последовательность кодовых единиц UTF-16. (К сожалению, термин Unicode был неправильно использован в Encoding.Unicode и в Win32 API. Unicode - это набор символов, а не кодировка. UTF-16 - одна из нескольких кодировок для Unicode.)   -  person Tom Blodget    schedule 19.11.2016
comment
Вы делаете некорректное действие: делаете массив байтов в кодировке utf8, но читаете их с помощью iso decode. Если вы хотите создать строку с закодированными символами, просто вызовите string msg = iso.GetString (iso.GetBytes (Message));   -  person StuS    schedule 06.09.2017
comment
Это называется моджибаке.   -  person Rick James    schedule 13.07.2018
comment
Я предполагаю, что Даниил говорит, что Message был декодирован из UTF-8. Предполагая, что эта часть работает правильно, преобразование в Latin-1 так же просто, как byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(Message). Затем, как говорит StuS, вы можете преобразовать байты Latin-1 обратно в UTF-16 с помощью Encoding.GetEncoding("ISO-8859-1").GetString(bytes)   -  person Qwertie    schedule 30.10.2019


Ответы (8)


Используйте Encoding.Convert для настройки массива байтов. прежде чем пытаться декодировать его в целевую кодировку.

Encoding iso = Encoding.GetEncoding("ISO-8859-1");
Encoding utf8 = Encoding.UTF8;
byte[] utfBytes = utf8.GetBytes(Message);
byte[] isoBytes = Encoding.Convert(utf8, iso, utfBytes);
string msg = iso.GetString(isoBytes);
person Nathan Baulch    schedule 17.12.2009
comment
Один лайнер Encoding.GetEncoding("ISO-8859-1").GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), Encoding.UTF8.GetBytes(myString))) - person ; 11.12.2015
comment
Если вы сами создаете строку внутри C # /. Net, то этот код не на 100% правильный, вам нужно кодировать из UTF-16 (это переменная Unicode). Потому что это по умолчанию. Поэтому UTF8 в приведенном выше коде необходимо изменить на Unicode. - person goamn; 01.06.2017
comment
Я рекомендую использовать это: Encoding iso = Encoding.GetEncoding (ISO-8859-9); Потому что турецкая кодировка охватывает почти весь алфавит, заимствованный из латиницы. - person Fuat; 31.08.2018
comment
Вы знаете, isoBytes тоже просто iso.GetBytes(Message);. Здесь не нужно ничего конвертировать. Фактически, вы можете просто пропустить все это и сказать string msg = Message. Нет никакого реального смысла в каких-либо этих преобразованиях, так как начало и конец - это просто .Net String. И текстовые кодировки не имеют значения для .Net String, если вам не нужно обрабатывать его как байты. - person Nyerguds; 02.11.2020

Я думаю, ваша проблема в том, что вы предполагаете, что байты, представляющие строку utf8, приведут к той же строке при интерпретации как что-то еще (iso-8859-1). А это просто не так. Я рекомендую вам прочитать эту отличную статью Джоэла Спольски.

person Klaus Byskov Pedersen    schedule 17.12.2009
comment
Действительно отличная статья и с чувством юмора! Сегодня я столкнулся с проблемой кодирования на работе, и это помогло мне. - person Pantelis; 23.08.2012

Попробуй это:

Encoding iso = Encoding.GetEncoding("ISO-8859-1");
Encoding utf8 = Encoding.UTF8;
byte[] utfBytes = utf8.GetBytes(Message);
byte[] isoBytes = Encoding.Convert(utf8,iso,utfBytes);
string msg = iso.GetString(isoBytes);
person Manu    schedule 17.12.2009
comment
почему я получаю такое же сообщение utf-8? вместо сообщения я передал строку message = ‹name› sdjfhsjdf ‹/name›. затем такой же вывод появляется в msg varieable. как получить латинские данные? - person user1237131; 09.01.2013
comment
У меня это работает. Не забудьте включить пространство имен System.Text. - person Spawnrider; 03.06.2013
comment
Encoding.Convert генерирует резервное исключение при преобразовании, если строка содержит символы, отличные от iso - person Tertium; 15.05.2014

В первую очередь вам нужно исправить источник строки.

Строка в .NET на самом деле представляет собой просто массив 16-битных кодовых точек Unicode, символов, поэтому строка не находится в какой-либо конкретной кодировке.

Кодирование вступает в игру, когда вы берете эту строку и конвертируете ее в набор байтов.

В любом случае, как вы это сделали, закодировав строку в массив байтов с одним набором символов, а затем декодировав ее другим, как вы видите, не сработает.

Не могли бы вы рассказать нам больше о том, откуда взялась эта исходная строка и почему, по вашему мнению, она была неправильно закодирована?

person Lasse V. Karlsen    schedule 17.12.2009
comment
Он идет прямо из App.config, и я думал, что по умолчанию это UTF8. Благодарю вас! - person Daniil Harik; 17.12.2009
comment
Кодировка этого файла может повлиять на его интерпретацию, поэтому я бы посмотрел на это. - person Lasse V. Karlsen; 17.12.2009
comment
Поправьте меня, если я ошибаюсь, но я понимаю, что, хотя технически это не в какой-либо конкретной кодировке, строка .NET представляет собой массив байтов, который точно соответствует файлу UTF-16, байт за байтом (за исключением спецификации ). Он даже использует суррогаты таким же образом (что похоже на трюк с кодированием). Конечно, вы обычно хотите хранить файлы как UTF-8, но обрабатывать данные в памяти как 16-битные. (Или 32-битный, чтобы избежать сложности суррогатных пар, хотя я не уверен, действительно ли это возможно.) - person Jon Coombs; 27.09.2013
comment
@JonCoombs Я не думаю, что это правильно. UTF-16 работает с расширяющимися кодами операций. Строки .Net просто используют массив 16-битных кодовых точек без какого-либо расширения. Насколько мне известно, он поддерживает только диапазон 0000-FFFF. - person Nyerguds; 02.11.2020

Кажется немного странным код. Чтобы получить строку из потока байтов Utf8, все, что вам нужно сделать, это:

string str = Encoding.UTF8.GetString(utf8ByteArray);

Если вам нужно где-то сохранить поток байтов iso-8859-1, просто используйте: дополнительную строку кода для предыдущего:

byte[] iso88591data = Encoding.GetEncoding("ISO-8859-1").GetBytes(str);
person Sander A    schedule 13.06.2014
comment
Это явно самый простой ответ. Проблема в коде действительно заключается в том, что автор, кажется, предполагает, что String в C # уже может быть сохранен с использованием определенной кодировки, что попросту неверно; они всегда внутри UTF16. - person Nyerguds; 14.03.2016
comment
Полностью согласен. Когда у вас уже есть UTF-16, довольно сложно преобразовать его в правильную кодировку, потому что при преобразовании массива байтов в строку с неправильной кодировкой уже происходит потеря информации. - person Sander A; 18.03.2016

Просто использовал раствор Натана, и он отлично работает. Мне нужно было преобразовать ISO-8859-1 в Unicode:

string isocontent = Encoding.GetEncoding("ISO-8859-1").GetString(fileContent, 0, fileContent.Length);
byte[] isobytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(isocontent);
byte[] ubytes = Encoding.Convert(Encoding.GetEncoding("ISO-8859-1"), Encoding.Unicode, isobytes);
return Encoding.Unicode.GetString(ubytes, 0, ubytes.Length);
person Nicolai Nita    schedule 27.06.2014

Может быть, это поможет
Преобразовать одну кодовую страницу в другую:

    public static string fnStringConverterCodepage(string sText, string sCodepageIn = "ISO-8859-8", string sCodepageOut="ISO-8859-8")
    {
        string sResultado = string.Empty;
        try
        {
            byte[] tempBytes;
            tempBytes = System.Text.Encoding.GetEncoding(sCodepageIn).GetBytes(sText);
            sResultado = System.Text.Encoding.GetEncoding(sCodepageOut).GetString(tempBytes);
        }
        catch (Exception)
        {
            sResultado = "";
        }
        return sResultado;
    }

Использование:

string sMsg = "ERRO: Não foi possivel acessar o servico de Autenticação";
var sOut = fnStringConverterCodepage(sMsg ,"ISO-8859-1","UTF-8"));

Выход:

"Não foi possivel acessar o servico de Autenticação"
person nandox    schedule 18.12.2020

Вот образец для ISO-8859-9;

protected void btnKaydet_Click(object sender, EventArgs e)
{
    Response.Clear();
    Response.Buffer = true;
    Response.ContentType = "application/vnd.openxmlformatsofficedocument.wordprocessingml.documet";
    Response.AddHeader("Content-Disposition", "attachment; filename=XXXX.doc");
    Response.ContentEncoding = Encoding.GetEncoding("ISO-8859-9");
    Response.Charset = "ISO-8859-9";
    EnableViewState = false;


    StringWriter writer = new StringWriter();
    HtmlTextWriter html = new HtmlTextWriter(writer);
    form1.RenderControl(html);


    byte[] bytesInStream = Encoding.GetEncoding("iso-8859-9").GetBytes(writer.ToString());
    MemoryStream memoryStream = new MemoryStream(bytesInStream);


    string msgBody = "";
    string Email = "[email protected]";
    SmtpClient client = new SmtpClient("mail.xxxxx.org");
    MailMessage message = new MailMessage(Email, "[email protected]", "ONLINE APP FORM WITH WORD DOC", msgBody);
    Attachment att = new Attachment(memoryStream, "XXXX.doc", "application/vnd.openxmlformatsofficedocument.wordprocessingml.documet");
    message.Attachments.Add(att);
    message.BodyEncoding = System.Text.Encoding.UTF8;
    message.IsBodyHtml = true;
    client.Send(message);}
person Engin Kamarot    schedule 17.09.2015