C # Convertir cadena de UTF-8 a ISO-8859-1 (Latin1) H

103

Busqué en Google sobre este tema y miré todas las respuestas, pero todavía no lo entiendo.

Básicamente, necesito convertir la cadena UTF-8 a ISO-8859-1 y lo hago usando el siguiente código:

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

Mi cadena de origen es

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

Pero desafortunadamente mi cadena de resultados se convierte en

msg = "�ä�ö�õ�ü

¿Qué estoy haciendo mal aquí?

Daniil Harik
fuente
5
Todas las cadenas de .NET almacenan internamente las cadenas con caracteres Unicode. No existe la noción de que una cadena sea "windows-1252", "iso-8859-1", "utf-8", etc. ¿Está tratando de descartar algún carácter de su cadena que no tenga una representación en Windows? -1252 página de códigos?
Ian Boyd
1
@IanBoyd En realidad, una cadena es una secuencia contada de unidades de código UTF-16. (Desafortunadamente, el término Unicode se ha aplicado incorrectamente en Encoding.Unicodela API de Win32. Unicode es un conjunto de caracteres, no una codificación. UTF-16 es una de varias codificaciones para Unicode).
Tom Blodget
1
Realiza una acción incorrecta: crea una matriz de bytes en la codificación utf8, pero los lee mediante decodificación iso. Si desea hacer una cadena con símbolos codificados, simplemente llame a la cadena msg = iso.GetString (iso.GetBytes (Message));
StuS
Eso se llama Mojibake.
Rick James
Supongo que lo que dice Daniil es que Messagefue decodificado de UTF-8. Suponiendo que esa parte funcionó correctamente, convertir a Latin-1 es tan simple como byte[] bytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(Message). Luego, como dice StuS, puede convertir los bytes Latin-1 nuevamente a UTF-16 conEncoding.GetEncoding("ISO-8859-1").GetString(bytes)
Qwertie

Respuestas:

176

Utilice Encoding.Convert para ajustar la matriz de bytes antes de intentar decodificarla en su codificación 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
fuente
7
La única línea esEncoding.GetEncoding("ISO-8859-1").GetString(Encoding.Convert(Encoding.UTF8, Encoding.GetEncoding("ISO-8859-1"), Encoding.UTF8.GetBytes(myString)))
1
Si está creando la cadena usted mismo dentro de C # /. Net, entonces este código no es 100% correcto, debe codificar desde UTF-16 (que es la variable "Unicode"). Porque este es el predeterminado. Entonces, UTF8 en el código anterior debe cambiarse a Unicode.
goamn
Recomiendo usar esto: Encoding iso = Encoding.GetEncoding ("ISO-8859-9"); Porque la codificación turca cubre casi todo el alfabeto extendido del latín.
Fuat
26

Creo que su problema es que asume que los bytes que representan la cadena utf8 resultarán en la misma cadena cuando se interpreten como otra cosa (iso-8859-1). Y ese simplemente no es el caso. Te recomiendo que leas este excelente artículo de Joel spolsky.

Klaus Byskov Pedersen
fuente
1
¡Excelente artículo y con sentido del humor! Hoy me enfrentaba a un problema de codificación en el trabajo y esto me ayudó.
Pantelis
16

Prueba esto:

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
fuente
¿Por qué recibo el mismo mensaje utf-8? En lugar del mensaje pasé string message = <name> sdjfhsjdf </name> .Entonces, la misma salida se obtiene en msg varieable. ¿Cómo obtener datos latinos?
user1237131
Esto funciona para mi. Recuerde incluir el espacio de nombres System.Text.
Spawnrider
2
Encoding.Convert arroja una excepción de respaldo al convertir si la cadena tiene caracteres que no son iso
Tertium
8

Necesita arreglar la fuente de la cadena en primer lugar.

Una cadena en .NET es en realidad solo una matriz de caracteres, puntos de código Unicode de 16 bits, por lo que una cadena no tiene ninguna codificación en particular.

Es cuando tomas esa cadena y la conviertes en un conjunto de bytes que entra en juego la codificación.

En cualquier caso, la forma en que lo hizo, codificó una cadena en una matriz de bytes con un conjunto de caracteres y luego la decodificación con otro, no funcionará, como puede ver.

¿Puede decirnos más sobre el origen de esa cadena original y por qué cree que se ha codificado mal?

Lasse V. Karlsen
fuente
Viene directamente de App.config y estaba pensando que es UTF8 por defecto. ¡Gracias!
Daniil Harik
La codificación de ese archivo podría afectar la forma en que se interpreta el archivo, así que miraría eso.
Lasse V. Karlsen
2
Corríjame si me equivoco, pero tengo entendido que, aunque técnicamente "no tiene ninguna codificación en particular", una cadena .NET es una matriz de bytes que corresponde precisamente a un archivo UTF-16, byte por byte (excluyendo la lista de materiales). Incluso usa sustitutos de la misma manera (lo que parece un truco de codificación). Por supuesto, generalmente desea almacenar archivos como UTF-8 pero procesar los datos en la memoria como 16 bits. (O 32 bits, para evitar la complejidad de los pares suplentes, aunque no estoy seguro de si eso es realmente factible.)
Jon Coombs
6

Parece un código un poco extraño. Para obtener una cadena del flujo de bytes Utf8, todo lo que necesita hacer es:

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

Si necesita guardar el flujo de bytes iso-8859-1 en algún lugar, simplemente use: línea adicional de código para el anterior:

byte[] iso88591data = Encoding.GetEncoding("ISO-8859-1").GetBytes(str);
Lijadora A
fuente
1
Esta es claramente la respuesta más sencilla. El problema en el código es que, de hecho, el autor parece suponer que una cadena en C # ya se puede almacenar "usando" una determinada codificación, lo que simplemente no es cierto; siempre son UTF16 internamente.
Nyerguds
1
Completamente de acuerdo. Cuando ya tiene UTF-16, es bastante difícil convertirlo en la codificación correcta, porque cuando convierte una matriz de bytes en una cadena con una codificación incorrecta, ya hay pérdida de información.
Sander A
0

Solo usé la solución de Nathan y funciona bien. Necesitaba convertir ISO-8859-1 a 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
fuente
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
fuente
-5

Aquí hay una muestra 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
fuente