C # Konwertuj ciąg z UTF-8 na ISO-8859-1 (Latin1) H

103

Poszukałem w Google na ten temat i sprawdziłem każdą odpowiedź, ale nadal jej nie rozumiem.

Zasadniczo muszę przekonwertować ciąg UTF-8 na ISO-8859-1 i robię to za pomocą następującego kodu:

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

Mój ciąg źródłowy to

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

Niestety, mój ciąg wynikowy to

msg = "�ä�ö�õ�ü

Co tu robię źle?

Daniil Harik
źródło
5
Wszystkie ciągi w .NET przechowują wewnętrznie ciągi przy użyciu znaków Unicode. Nie ma pojęcia, że ​​Łańcuch to "windows-1252", "iso-8859-1", "utf-8" itp. Czy próbujesz wyrzucić jakiekolwiek znaki ze swojego ciągu, które nie mają reprezentacji w systemie Windows -1252 strona kodowa?
Ian Boyd,
1
@IanBoyd Właściwie łańcuch jest policzoną sekwencją jednostek kodu UTF-16. (Niestety, termin Unicode został niewłaściwie zastosowany w Encoding.Unicodei w Win32 API. Unicode to zestaw znaków, a nie kodowanie. UTF-16 jest jednym z kilku kodowań Unicode.)
Tom Blodget
1
Wykonujesz niepoprawne działanie: tworzysz tablicę bajtów w kodowaniu utf8, ale odczytujesz je za pomocą dekodowania ISO. Jeśli chcesz utworzyć łańcuch z zakodowanymi symbolami, po prostu wywołaj string msg = iso.GetString (iso.GetBytes (Message));
StuS,
To się nazywa Mojibake.
Rick James,
Wydaje mi się, że Daniil mówi, że Messagezostał zdekodowany z UTF-8. Zakładając, że ta część działała poprawnie, konwersja na Latin-1 jest tak prosta jak byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(Message). Następnie, jak mówi StuS, możesz przekonwertować bajty Latin-1 z powrotem na UTF-16 za pomocąEncoding.GetEncoding("ISO-8859-1").GetString(bytes)
Qwertie

Odpowiedzi:

176

Użyj Encoding.Convert, aby dostosować tablicę bajtów przed próbą zdekodowania jej do kodowania docelowego.

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);
Nathan Baulch
źródło
7
Jedna linijka toEncoding.GetEncoding("ISO-8859-1").GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), Encoding.UTF8.GetBytes(myString)))
1
Jeśli sam tworzysz ciąg w C # / .Net, to ten kod nie jest w 100% poprawny, musisz zakodować z UTF-16 (który jest zmienną „Unicode”). Ponieważ jest to ustawienie domyślne. Zatem UTF8 w powyższym kodzie należy zmienić na Unicode.
goamn
Zalecam użycie tego: Encoding iso = Encoding.GetEncoding ("ISO-8859-9"); Ponieważ kodowanie w języku tureckim obejmuje prawie cały alfabet rozszerzony z łaciny.
Fuat
26

Myślę, że twój problem polega na tym, że zakładasz, że bajty reprezentujące łańcuch utf8 dadzą ten sam ciąg, gdy zostaną zinterpretowane jako coś innego (iso-8859-1). A tak po prostu nie jest. Polecam przeczytanie tego znakomitego artykułu Joela Spolsky'ego.

Klaus Byskov Pedersen
źródło
1
Doprawdy świetny artykuł iz poczuciem humoru! Miałem dziś w pracy problem z kodowaniem i to mi pomogło.
Pantelis
16

Spróbuj tego:

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);
Manu
źródło
dlaczego otrzymuję tę samą wiadomość utf-8? zamiast wiadomości przekazałem wiadomość tekstową = <nazwa> sdjfhsjdf </name>. Następnie te same dane wyjściowe w msg varieable.jak uzyskać dane łacińskie?
user1237131
To działa dla mnie. Pamiętaj, aby uwzględnić przestrzeń nazw System.Text.
Spawnrider
2
Encoding.Convert zgłasza wyjątek rezerwowy podczas konwersji, jeśli łańcuch zawiera znaki inne niż iso
Tertium
8

W pierwszej kolejności musisz naprawić źródło łańcucha.

Łańcuch w .NET jest w rzeczywistości tablicą 16-bitowych punktów kodowych Unicode, znaków, więc ciąg nie jest w żadnym konkretnym kodowaniu.

Kodowanie zaczyna się wtedy, gdy bierzesz ten ciąg i konwertujesz go na zestaw bajtów.

W każdym razie sposób, w jaki to zrobiłeś, zakodował łańcuch do tablicy bajtów z jednym zestawem znaków, a następnie zdekodował go innym, nie zadziała, jak widzisz.

Czy możesz nam powiedzieć więcej o tym, skąd pochodzi ten oryginalny ciąg i dlaczego uważasz, że został nieprawidłowo zakodowany?

Lasse V. Karlsen
źródło
Pochodzi bezpośrednio z App.config i myślałem, że domyślnie jest to UTF8. Dziękuję Ci!
Daniil Harik
Kodowanie tego pliku może mieć wpływ na sposób interpretacji pliku, więc przyjrzę się temu.
Lasse V. Karlsen
2
Popraw mnie, jeśli się mylę, ale rozumiem, że chociaż technicznie nie jest to żadne szczególne kodowanie, ciąg .NET jest tablicą bajtów, która dokładnie odpowiada plikowi UTF-16, bajt po bajcie (z wyłączeniem zestawienie komponentów). Używa nawet surogatów w ten sam sposób (co wydaje się być sztuczką kodowania). Oczywiście zazwyczaj chcesz przechowywać pliki w formacie UTF-8, ale przetwarzać dane w pamięci jako 16-bitowe. (Lub 32-bitowe, aby uniknąć złożoności par zastępczych, chociaż nie jestem pewien, czy to naprawdę wykonalne.)
Jon Coombs
6

Wydaje się trochę dziwny kod. Aby pobrać ciąg ze strumienia bajtów Utf8, wszystko, co musisz zrobić, to:

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

Jeśli chcesz zapisać strumień bajtów iso-8859-1 gdzieś, po prostu użyj: dodatkowej linii kodu dla poprzedniego:

byte[] iso88591data = Encoding.GetEncoding("ISO-8859-1").GetBytes(str);
Sander A
źródło
1
To zdecydowanie najprostsza odpowiedź. Problem w kodzie polega w istocie na tym, że autor wydaje się zakładać, że ciąg znaków w C # może już być przechowywany „przy użyciu” określonego kodowania, co po prostu nie jest prawdą; są zawsze wewnętrznie UTF16.
Nyerguds
1
W pełni się zgadzam. Gdy masz już UTF-16, dość trudno jest przekształcić to w poprawne kodowanie, ponieważ po przekonwertowaniu tablicy bajtów na ciąg znaków z niewłaściwym kodowaniem następuje już utrata informacji.
Sander A,
0

Po prostu użyłem rozwiązania Nathana i działa dobrze. Musiałem przekonwertować ISO-8859-1 na 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);
Nicolai Nita
źródło
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);
Tomáš Opis
źródło
-5

Oto przykład dla 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);}
Engin Kamarot
źródło