¿Cómo puedo transformar la cadena a UTF-8 en C #?

146

Tengo una cadena que recibo de una aplicación de terceros y me gustaría mostrarla correctamente en cualquier idioma usando C # en mi Windows Surface.

Debido a una codificación incorrecta, una parte de mi cadena se ve así en español:

Acción

mientras que debería verse así:

Acción

De acuerdo con la respuesta a esta pregunta: Cómo saber la codificación de cadenas en C # , la codificación que estoy recibiendo ya debería estar en UTF-8, pero se lee en Codificación. Predeterminado (¿probablemente ANSI?).

Estoy tratando de transformar esta cadena en UTF-8 real, pero uno de los problemas es que solo puedo ver un subconjunto de la clase de codificación (solo propiedades UTF8 y Unicode), probablemente porque estoy limitado a la API de superficie de Windows.

He probado algunos fragmentos que he encontrado en Internet, pero ninguno de ellos ha tenido éxito hasta ahora para los idiomas orientales (es decir, coreano). Un ejemplo es el siguiente:

var utf8 = Encoding.UTF8;
byte[] utfBytes = utf8.GetBytes(myString);
myString= utf8.GetString(utfBytes, 0, utfBytes.Length);     

También intenté extraer la cadena en una matriz de bytes y luego usar UTF8.GetString:

byte[] myByteArray = new byte[myString.Length];
for (int ix = 0; ix < myString.Length; ++ix)
{
    char ch = myString[ix];
    myByteArray[ix] = (byte) ch;
}

myString = Encoding.UTF8.GetString(myByteArray, 0, myString.Length);

¿Ustedes tienen alguna otra idea que pueda probar?

Gaara
fuente
55
Su problema proviene del código que creó la cadena (de una secuencia o byte []) en primer lugar. Por favor muestra ese código.
SLaks
1
@Oded: las cadenas .Net se almacenan en la memoria como UTF16, pero Encoding.Defaultdevuelve la página de códigos ANSI del sistema.
SLaks
Aquí hay un ejemplo de una cadena que no funciona en inglés: en lugar de mostrar el día, mi aplicación front-end muestra: día
Gaara

Respuestas:

251

Como saben, la cadena está entrando, ya Encoding.Defaultque simplemente podría usar:

byte[] bytes = Encoding.Default.GetBytes(myString);
myString = Encoding.UTF8.GetString(bytes);

Otra cosa que quizás tenga que recordar: si está utilizando Console.WriteLine para generar algunas cadenas, ¡también debe escribir Console.OutputEncoding = System.Text.Encoding.UTF8;! O todas las cadenas utf8 serán superadas como gbk ...

otro derrochador
fuente
Esto también funciona en realidad es mucho mejor que mi respuesta, que también trabaja Te estoy dando una obra agradable 1
MethodMan
¡Gracias! El problema es que, como mencioné en la descripción, la API para la superficie está incompleta (no hay codificación disponible por defecto).
Gaara
3
@Gaara: Prueba Encoding.GetEncoding(...); necesitará encontrar el nombre de la codificación real que se usó incorrectamente en el otro extremo.
SLaks
1
¿Puedes explicar por qué esto funciona? si el valor predeterminado es GB2312, entonces Encoding.Default.GetBytes codificará la cadena para la matriz de bytes con el codificador GB2312, luego Encoding.UTF8.GetString intentará decodificar la matriz de bytes con el decodificador UTF8, el resultado debería ser incorrecto, pero por qué esto funciona. @anothershrubery
guorongfei
1
@guorongfei La premisa es que myStringes mojibake. El código primero deshace la decodificación incorrecta y luego realiza la decodificación correcta. Funciona siempre que la decodificación incorrecta no haya perdido datos. Pero como señaló @SLaks, sería mejor usar la codificación exacta que estaba mal. (Los mejores nombres y comentarios en el código ayudarían a comprender cómo un código que se ve muy mal en realidad es un intento de hacer lo correcto.)
Tom Blodget
18
string utf8String = "Acción";
string propEncodeString = string.Empty;

byte[] utf8_Bytes = new byte[utf8String.Length];
for (int i = 0; i < utf8String.Length; ++i)
{
   utf8_Bytes[i] = (byte)utf8String[i];
}

propEncodeString = Encoding.UTF8.GetString(utf8_Bytes, 0, utf8_Bytes.Length);

La salida debería verse como

Acción

día muestra el día

llame a DecodeFromUtf8 ();

private static void DecodeFromUtf8()
{
    string utf8_String = "day’s";
    byte[] bytes = Encoding.Default.GetBytes(utf8_String);
    utf8_String = Encoding.UTF8.GetString(bytes);
}
Hombre de método
fuente
1
¡Gracias! Funciona en español, el problema es que lo mismo no funcionaría en idiomas orientales (es decir, coreano). Estoy tratando de buscar un algoritmo de conversión de 8 bits a UTF-8 en Internet, pero todavía no tengo suerte.
Gaara
Aquí hay un ejemplo de una cadena que no funciona en inglés: en lugar de mostrar el día, mi aplicación front-end muestra: día
Gaara
ok déjame jugar con eso y ver qué puedo hacer
MethodMan
Probé y regresa el día
Pegaré
puede alterar ese método pasando DecodeFromUtf8 (string utf8string);
MethodMan
12

Su código lee una secuencia de bytes codificados en UTF8 y los decodifica con una codificación de 8 bits.

Debe corregir ese código para decodificar los bytes como UTF8.

Alternativamente ( no ideal ), puede convertir la cadena incorrecta de nuevo a la matriz de bytes original, codificándola con la codificación incorrecta, y luego volver a decodificar los bytes como UTF8.

SLaks
fuente
¡Gracias! El problema es que la aplicación de terceros es C ++, mientras que mi código es C #, así que supongo que la decodificación ocurre en el "puente" entre esos dos.
Gaara
8
 Encoding.Convert(Encoding.Default, Encoding.UTF8, Encoding.Default.GetBytes(mystring));
Riadh Hammouda
fuente
5

Si desea guardar cualquier cadena en la base de datos mysql, haga esto: ->

La estructura de campo de su base de datos i phpmyadmin [o cualquier otro panel de control] debe establecerse en utf8-gerneral-ci

2) debes cambiar tu cadena [Ej. textbox1.text] a byte, por lo tanto

2-1) define el byte [] st2;

2-2) convierta su cadena [textbox1.text] a unicode [cadena de mmultibyte] por:

byte[] st2 = System.Text.Encoding.UTF8.GetBytes(textBox1.Text);

3) ejecute este comando sql antes de cualquier consulta:

string mysql_query2 = "SET NAMES 'utf8'";
cmd.CommandText = mysql_query2;
cmd.ExecuteNonQuery();

3-2) ahora debe insertar este valor en, por ejemplo, el campo de nombre:

cmd.CommandText = "INSERT INTO customer (`name`) values (@name)";

4) el trabajo principal al que muchas soluciones no le prestaron atención es la siguiente línea: debe usar addwithvalue en lugar de agregar el parámetro de comando como a continuación:

cmd.Parameters.AddWithValue("@name",ut);

++++++++++++++++++++++++++++++++++ disfrutan de datos reales en su servidor de base de datos en lugar de ????

Hassan Fadaie Ghotbie
fuente
3

Use el fragmento de código a continuación para obtener bytes del archivo csv

protected byte[] GetCSVFileContent(string fileName)
    {
        StringBuilder sb = new StringBuilder();
        using (StreamReader sr = new StreamReader(fileName, Encoding.Default, true))
        {
            String line;
            // Read and display lines from the file until the end of 
            // the file is reached.
            while ((line = sr.ReadLine()) != null)
            {
                sb.AppendLine(line);
            }
        }
        string allines = sb.ToString();


        UTF8Encoding utf8 = new UTF8Encoding();


        var preamble = utf8.GetPreamble();

        var data = utf8.GetBytes(allines);


        return data;
    }

Llame al siguiente y guárdelo como un archivo adjunto

           Encoding csvEncoding = Encoding.UTF8;
                   //byte[] csvFile = GetCSVFileContent(FileUpload1.PostedFile.FileName);
          byte[] csvFile = GetCSVFileContent("Your_CSV_File_NAme");


        string attachment = String.Format("attachment; filename={0}.csv", "uomEncoded");

        Response.Clear();
        Response.ClearHeaders();
        Response.ClearContent();
        Response.ContentType = "text/csv";
        Response.ContentEncoding = csvEncoding;
        Response.AppendHeader("Content-Disposition", attachment);
        //Response.BinaryWrite(csvEncoding.GetPreamble());
        Response.BinaryWrite(csvFile);
        Response.Flush();
        Response.End();
jAntoni
fuente