¿Cómo convertir una cadena UTF-8 en Unicode?

Tengo un string que muestra caracteres codificados en UTF-8, y quiero convertirlo a Unicode.

Por ahora, mi implementación es la siguiente:

public static string DecodeFromUtf8(this string utf8String) { // read the string as UTF-8 bytes. byte[] encodedBytes = Encoding.UTF8.GetBytes(utf8String); // convert them into unicode bytes. byte[] unicodeBytes = Encoding.Convert(Encoding.UTF8, Encoding.Unicode, encodedBytes); // builds the converted string. return Encoding.Unicode.GetString(encodedBytes); } 

Estoy jugando con la palabra "déjà" . Lo convertí en UTF-8 a través de esta herramienta en línea , así que comencé a probar mi método con la cadena "déjÃ" .

Desafortunadamente, con esta implementación, la cadena sigue siendo la misma.

¿Dónde estoy equivocado?

Entonces, el problema es que los valores de unidad de código UTF-8 se han almacenado como una secuencia de unidades de código de 16 bits en una string C #. Simplemente necesita verificar que cada unidad de código se encuentre dentro del rango de un byte, copie esos valores en bytes y luego convierta la nueva secuencia de bytes UTF-8 en UTF-16.

 public static string DecodeFromUtf8(this string utf8String) { // copy the string as UTF-8 bytes. byte[] utf8Bytes = new byte[utf8String.Length]; for (int i=0;i 

Esto es fácil, sin embargo, sería mejor encontrar la causa raíz; la ubicación donde alguien está copiando unidades de código UTF-8 en unidades de códigos de 16 bits. El posible culpable es alguien convirtiendo bytes en una string C # utilizando la encoding incorrecta. Por ejemplo, Encoding.Default.GetString(utf8Bytes, 0, utf8Bytes.Length) .


Alternativamente, si está seguro de que conoce la encoding incorrecta que se utilizó para producir la cadena, y que la transformación de encoding incorrecta fue sin pérdida (generalmente el caso si la encoding incorrecta es una encoding de un solo byte), simplemente puede hacer la encoding inversa paso para obtener los datos UTF-8 originales, y luego puede hacer la conversión correcta de los bytes UTF-8:

 public static string UndoEncodingMistake(string mangledString, Encoding mistake, Encoding correction) { // the inverse of `mistake.GetString(originalBytes);` byte[] originalBytes = mistake.GetBytes(mangledString); return correction.GetString(originalBytes); } UndoEncodingMistake("d\u00C3\u00A9j\u00C3\u00A0", Encoding(1252), Encoding.UTF8); 

Si tiene una cadena UTF-8, donde cada byte es correcto (‘Ö’ -> [195, 0], [150, 0]), puede usar lo siguiente:

 public static string Utf8ToUtf16(string utf8String) { /*************************************************************** * Every .NET string will store text with the UTF-16 encoding, * * known as Encoding.Unicode. Other encodings may exist as * * Byte-Array or incorrectly stored with the UTF-16 encoding. * * * * UTF-8 = 1 bytes per char * * ["100" for the ansi 'd'] * * ["206" and "186" for the russian '?'] * * * * UTF-16 = 2 bytes per char * * ["100, 0" for the ansi 'd'] * * ["186, 3" for the russian '?'] * * * * UTF-8 inside UTF-16 * * ["100, 0" for the ansi 'd'] * * ["206, 0" and "186, 0" for the russian '?'] * * * * First we need to get the UTF-8 Byte-Array and remove all * * 0 byte (binary 0) while doing so. * * * * Binary 0 means end of string on UTF-8 encoding while on * * UTF-16 one binary 0 does not end the string. Only if there * * are 2 binary 0, than the UTF-16 encoding will end the * * string. Because of .NET we don't have to handle this. * * * * After removing binary 0 and receiving the Byte-Array, we * * can use the UTF-8 encoding to string method now to get a * * UTF-16 string. * * * ***************************************************************/ // Get UTF-8 bytes and remove binary 0 bytes (filler) List utf8Bytes = new List(utf8String.Length); foreach (byte utf8Byte in utf8String) { // Remove binary 0 bytes (filler) if (utf8Byte > 0) { utf8Bytes.Add(utf8Byte); } } // Convert UTF-8 bytes to UTF-16 string return Encoding.UTF8.GetString(utf8Bytes.ToArray()); } 

En mi caso, el resultado de la DLL es una cadena UTF-8 también, pero desafortunadamente la cadena UTF-8 se interpreta con encoding UTF-16 (‘Ö’ -> [195, 0], [19, 32]). Entonces, el ANSI ‘-‘ que es 150 se convirtió al UTF-16 ‘-‘ que es 8211. Si tiene este caso también, puede usar lo siguiente:

 public static string Utf8ToUtf16(string utf8String) { // Get UTF-8 bytes by reading each byte with ANSI encoding byte[] utf8Bytes = Encoding.Default.GetBytes(utf8String); // Convert UTF-8 bytes to UTF-16 bytes byte[] utf16Bytes = Encoding.Convert(Encoding.UTF8, Encoding.Unicode, utf8Bytes); // Return UTF-16 bytes as UTF-16 string return Encoding.Unicode.GetString(utf16Bytes); } 

O el método nativo:

 [DllImport("kernel32.dll")] private static extern Int32 MultiByteToWideChar(UInt32 CodePage, UInt32 dwFlags, [MarshalAs(UnmanagedType.LPStr)] String lpMultiByteStr, Int32 cbMultiByte, [Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder lpWideCharStr, Int32 cchWideChar); public static string Utf8ToUtf16(string utf8String) { Int32 iNewDataLen = MultiByteToWideChar(Convert.ToUInt32(Encoding.UTF8.CodePage), 0, utf8String, -1, null, 0); if (iNewDataLen > 1) { StringBuilder utf16String = new StringBuilder(iNewDataLen); MultiByteToWideChar(Convert.ToUInt32(Encoding.UTF8.CodePage), 0, utf8String, -1, utf16String, utf16String.Capacity); return utf16String.ToString(); } else { return String.Empty; } } 

Si lo necesita al revés, vea Utf16ToUtf8 . Espero poder ser de ayuda.

Tengo una cadena que muestra caracteres codificados UTF-8

No existe tal cosa en .NET. La clase de cadena solo puede almacenar cadenas en encoding UTF-16. Una cadena codificada en UTF-8 solo puede existir como un byte []. Intentar almacenar bytes en una cadena no tendrá un buen final; UTF-8 usa valores de bytes que no tienen un punto de código Unicode válido. El contenido se destruirá cuando la cadena esté normalizada. Por lo tanto, ya es demasiado tarde para recuperar la cadena cuando su DecodeFromUtf8 () comience a ejecutarse.

Solo maneja texto codificado en UTF-8 con byte []. Y use UTF8Encoding.GetString () para convertirlo.

Lo que tiene parece ser una string decodificada incorrectamente desde otra encoding, probablemente la página de códigos 1252 , que es el valor predeterminado de Windows de EE. UU. A continuación, le mostramos cómo revertir, asumiendo que no hay otra pérdida. Una pérdida no aparente de inmediato es el non-breaking space (U + 00A0) al final de la cuerda que no se muestra. Por supuesto, sería mejor leer la fuente de datos correctamente en primer lugar, pero tal vez la fuente de datos se almacenó incorrectamente para empezar.

 using System; using System.Text; class Program { static void Main(string[] args) { string junk = "déjÃ\xa0"; // Bad Unicode string // Turn string back to bytes using the original, incorrect encoding. byte[] bytes = Encoding.GetEncoding(1252).GetBytes(junk); // Use the correct encoding this time to convert back to a string. string good = Encoding.UTF8.GetString(bytes); Console.WriteLine(good); } } 

Resultado:

 déjà