C # Перетворити рядок з UTF-8 в ISO-8859-1 (Latin1) H


103

Я погукав на цю тему і переглянув кожну відповідь, але все ще не розумію.

В основному мені потрібно перетворити рядок 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 = "�ä�ö�õ�ü

Що я тут роблю неправильно?


5
Усі рядки в .NET внутрішньо зберігають рядки, використовуючи символи unicode. Немає поняття, що "Рядок" є "windows-1252", "iso-8859-1", "utf-8" тощо. Чи намагаєтесь ви викинути будь-які символи в рядку, які не мають представлення в Windows -1252 сторінка коду?
Ян Бойд

1
@IanBoyd Власне, String - це підрахована послідовність кодових одиниць UTF-16. (На жаль, термін Unicode було неправильно застосовано в Encoding.UnicodeAPI Win32. Unicode - це набір символів, а не кодування. UTF-16 - це одне з декількох кодувань для Unicode.)
Том Блоджет

1
Ви робите неправильні дії: ви створюєте байтовий масив у кодування utf8, але читаєте їх за допомогою декодування iso. Якщо ви хочете зробити рядок з кодованими символами, це просто рядок
StuS

Це називається Mojibake.
Рік Джеймс

Я думаю, що Даніїл говорить, що це Messageбуло розшифровано з UTF-8. Якщо припустити, що частина працювала правильно, перехід на латинську-1 так само просто byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(Message). Тоді, як каже StuS, ви можете перетворити лайт-1 байт назад в UTF-16 за допомогоюEncoding.GetEncoding("ISO-8859-1").GetString(bytes)
Qwertie

Відповіді:


176

Використовуйте 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);

7
Один лайнерEncoding.GetEncoding("ISO-8859-1").GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), Encoding.UTF8.GetBytes(myString)))

1
Якщо ви створюєте рядок самостійно всередині C # /. Net, то цей код не на 100% правильний, вам потрібно кодувати з UTF-16 (що є змінною "Unicode"). Тому що це за замовчуванням. Отже UTF8 у наведеному вище коді має бути змінено на Unicode.
goamn

Я рекомендую використовувати таке: Encoding iso = Encoding.GetEncoding ("ISO-8859-9"); Тому що турецьке кодування охоплює майже весь алфавіт, поширений з латини.
Фуат

26

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


1
Чудова стаття справді і з почуттям гумору! Сьогодні я на роботі стикався з проблемою кодування, і це мені допомогло.
Pantelis

16

Спробуйте це:

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);

Чому я отримую те саме повідомлення utf-8? замість повідомлення я передав рядкове повідомлення = <ім'я> sdjfhsjdf </name>. тоді ж вихід, потрапляючи в msg varieable.how отримати латинські дані?
користувач1237131

Це працює для мене. Не забудьте включити простір імен System.Text.
Spawnrider

2
Encoding.Convert викидає винятковий запас під час перетворення, якщо рядок має символи, що не належать до ізо
Tertium

8

Вам потрібно в першу чергу виправити джерело рядка.

Рядок у .NET насправді є лише масивом 16-бітових кодових точок Unicode, символів, тому рядок не є в якомусь конкретному кодуванні.

Це коли ви берете цей рядок і перетворюєте його в набір байтів, які кодування вступає в гру.

У будь-якому випадку те, як ви це зробили, кодував рядок до байтового масиву з одним набором символів, а потім розшифрувавши його іншим, не буде працювати, як бачите.

Чи можете ви розповісти більше про те, звідки походить ця оригінальна рядок, і чому ви вважаєте, що вона була закодована неправильно?


Він надходить безпосередньо з App.config, і я думав, що це за замовчуванням UTF8. Спасибі!
Даніїл Харік

Кодування цього файлу може вплинути на інтерпретацію файлу, тому я б це зрозумів.
Лассе В. Карлсен

2
Виправте мене, якщо я помиляюся, але я розумію, що, хоча технічно це "не в якомусь конкретному кодуванні", .NET рядок - це байт-масив, що точно відповідає файлу UTF-16, байт для байта (виключаючи БОМ). Він навіть використовує сурогати таким же чином (що здається кодовим трюком). Звичайно, ти, як правило, хочеш зберігати файли як UTF-8, але обробляти дані в пам'яті як 16-бітні. (Або 32-розрядні, щоб уникнути складності сурогатних пар, хоча я не впевнений, чи реально це реально.)
Джон Кумбс,

6

Здається трохи дивним кодом. Щоб отримати рядок з потоку байтів Utf8, все, що вам потрібно зробити:

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

Якщо вам потрібно зберегти ізо-8859-1 байт-потік десь, тоді просто використовуйте: додатковий рядок коду для попереднього:

byte[] iso88591data = Encoding.GetEncoding("ISO-8859-1").GetBytes(str);

1
Це однозначно найпростіша відповідь. Проблема в коді справді полягає в тому, що автор, здається, припускає, що String в C # вже може бути збережений, "використовуючи" певне кодування, що просто не відповідає дійсності; вони завжди UTF16 всередині.
Nyerguds

1
Повністю згоден. Коли у вас вже є UTF-16, досить важко перетворити це на правильне кодування, оскільки при перетворенні байтового масиву в рядок з неправильним кодуванням вже втрачається інформація.
Сандер А

0

Щойно використав розчин Натана, і він прекрасно працює. Мені потрібно було перетворити 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);

0
Encoding targetEncoding = Encoding.GetEncoding(1252);
// Encode a string into an array of bytes.
Byte[] encodedBytes = targetEncoding.GetBytes(utfString);
// Show the encoded byte values.
Console.WriteLine("Encoded bytes: " + BitConverter.ToString(encodedBytes));
// Decode the byte array back to a string.
String decodedString = Encoding.Default.GetString(encodedBytes);

-5

Ось зразок для 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 = "mail@xxxxxx.org";
    SmtpClient client = new SmtpClient("mail.xxxxx.org");
    MailMessage message = new MailMessage(Email, "mail@someone.com", "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);}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.