C # Converter string de UTF-8 para ISO-8859-1 (Latin1) H

103

Eu pesquisei sobre esse assunto no Google e olhei todas as respostas, mas ainda não entendi.

Basicamente, preciso converter a string UTF-8 em ISO-8859-1 e faço isso usando o seguinte código:

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

Minha string fonte é

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

Mas, infelizmente, minha string de resultado se torna

msg = "�ä�ö�õ�ü

O que estou fazendo de errado aqui?

Daniil Harik
fonte
5
Todas as strings em .NET armazenam internamente as strings usando caracteres Unicode. Não há noção de uma string sendo "windows-1252", "iso-8859-1", "utf-8", etc. Você está tentando jogar fora algum caractere em sua string que não tenha uma representação no Windows -1252 página de código?
Ian Boyd
1
@IanBoyd Na verdade, uma String é uma sequência contada de unidades de código UTF-16. (Infelizmente, o termo Unicode foi mal aplicado na Encoding.UnicodeAPI Win32. Unicode é um conjunto de caracteres, não uma codificação. UTF-16 é uma das várias codificações para Unicode.)
Tom Blodget
1
Você comete uma ação incorreta: você cria um array de bytes na codificação utf8, mas os lê por decodificação iso. Se você quiser fazer uma string com símbolos codificados, basta
StuS
Isso é chamado de Mojibake.
Rick James
Eu acho que o que Daniil está dizendo é que Messagefoi decodificado de UTF-8. Assumindo que essa parte funcionou corretamente, a conversão para o Latin-1 é tão simples quanto byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(Message). Então, como StuS diz, você pode converter os bytes Latin-1 de volta para UTF-16 comEncoding.GetEncoding("ISO-8859-1").GetString(bytes)
Qwertie

Respostas:

176

Use Encoding.Convert para ajustar a matriz de bytes antes de tentar decodificá-la em sua codificação de destino.

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
fonte
7
O único forro éEncoding.GetEncoding("ISO-8859-1").GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), Encoding.UTF8.GetBytes(myString)))
1
Se você está criando a string dentro de C # / .Net, então este código não está 100% correto, você precisa codificar em UTF-16 (que é a variável "Unicode"). Porque este é o padrão. Portanto, UTF8 no código acima deve ser alterado para Unicode.
goamn 01 de
Eu recomendo usar isso: Encoding iso = Encoding.GetEncoding ("ISO-8859-9"); Porque a codificação turca cobre quase todo o alfabeto estendido do latim.
Fuat
26

Acho que seu problema é que você assume que os bytes que representam a string utf8 resultarão na mesma string quando interpretados como outra coisa (iso-8859-1). E isso simplesmente não é o caso. Recomendo que você leia este excelente artigo de Joel spolsky.

Klaus Byskov Pedersen
fonte
1
Excelente artigo mesmo e com senso de humor! Eu estava enfrentando um problema de codificação hoje no trabalho e isso me ajudou.
Pantelis
16

Experimente isto:

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
fonte
por que estou recebendo a mesma mensagem utf-8? no lugar da mensagem, passei a mensagem de string = <name> sdjfhsjdf </name> .então a mesma saída está sendo obtida em msg varieable.how para obter dados latinos?
user1237131
Isso funciona para mim. Lembre-se de incluir o namespace System.Text.
Spawnrider
2
Encoding.Convert lança exceção de fallback durante a conversão se a string tiver caracteres não iso
Tertium
8

Você precisa consertar a origem da corda em primeiro lugar.

Uma string no .NET é, na verdade, apenas uma matriz de pontos de código Unicode de 16 bits, caracteres, portanto, uma string não está em nenhuma codificação específica.

É quando você pega essa string e a converte em um conjunto de bytes que a codificação entra em ação.

Em qualquer caso, a maneira como você fez, codificar uma string em uma matriz de bytes com um conjunto de caracteres e depois decodificá-la com outro, não funcionará, como você pode ver.

Você pode nos contar mais sobre de onde vem a string original e por que você acha que foi codificada incorretamente?

Lasse V. Karlsen
fonte
Ele está vindo diretamente de App.config e eu estava pensando que é UTF8 por padrão. Obrigado!
Daniil Harik
A codificação desse arquivo pode afetar a forma como o arquivo é interpretado, então eu examinaria isso.
Lasse V. Karlsen
2
Corrija-me se eu estiver errado, mas meu entendimento é que, embora tecnicamente "não esteja em nenhuma codificação específica", uma string .NET é uma matriz de bytes que corresponde precisamente a um arquivo UTF-16, byte por byte (excluindo o BOM). Ele até usa substitutos da mesma maneira (o que parece um truque de codificação). Claro, você geralmente deseja armazenar arquivos como UTF-8, mas processar os dados na memória como 16 bits. (Ou 32 bits, para evitar a complexidade dos pares substitutos, embora eu não tenha certeza se isso é realmente viável.)
Jon Coombs
6

Parece um código um pouco estranho. Para obter a string do fluxo de bytes Utf8, tudo o que você precisa fazer é:

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

Se você precisar salvar o fluxo de bytes iso-8859-1 em algum lugar, basta usar: linha de código adicional para anterior:

byte[] iso88591data = Encoding.GetEncoding("ISO-8859-1").GetBytes(str);
Sander A
fonte
1
Esta é claramente a resposta mais direta. O problema no código é, de fato, que o autor parece assumir que uma String em C # já pode ser armazenada "usando" uma determinada codificação, o que simplesmente não é verdade; eles são sempre UTF16 internamente.
Nyerguds
1
Concordo plenamente. Quando você já tem UTF-16, é muito difícil codificar corretamente, porque quando você converte o array de bytes em string com a codificação errada, já ocorre perda de informações.
Sander A
0

Acabei de usar a solução do Nathan e funciona bem. Eu precisava converter ISO-8859-1 para 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
fonte
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
fonte
-5

Aqui está um exemplo para 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
fonte