2010-05-26 21 views
15

Tengo un problema al comparar cadenas en una prueba unitaria en C# 4.0 con Visual Studio 2010. Este mismo caso de prueba funciona correctamente en Visual Studio 2008 (con C# 3.5).¿Cómo ignoro el marcador de orden de bytes UTF-8 en las comparaciones de cadenas?

He aquí el fragmento de código relevante:

byte[] rawData = GetData(); 
string data = Encoding.UTF8.GetString(rawData); 

Assert.AreEqual("Constant", data, false, CultureInfo.InvariantCulture); 

Mientras se depura esta prueba, la cadena data parece a simple vista para contener exactamente la misma cadena que el literal. Cuando llamé al data.ToCharArray(), noté que el primer byte de la cadena data es el valor 65279 que es el marcador de orden de bytes UTF-8. Lo que no entiendo es por qué Encoding.UTF8.GetString() mantiene este byte alrededor.

¿Cómo consigo Encoding.UTF8.GetString() a no poner el marcador de orden de bytes en la cadena resultante?

Actualización: El problema era que GetData(), que lee un archivo desde el disco, lee los datos desde el archivo con FileStream.readbytes(). Corregí esto usando un StreamReader y convirtiendo la cadena a bytes usando Encoding.UTF8.GetBytes(), ¡que es lo que debería haber estado haciendo en primer lugar! Gracias por toda la ayuda.

+1

Se puede publicar un pequeño, pero completo, programa que demuestra el problema? –

Respuesta

16

Bueno, supongo que es porque los datos binarios sin procesar incluyen la lista de materiales. Siempre puede eliminar la BOM usted mismo después de la decodificación, si no lo desea, pero debe considerar si la matriz de bytes debe considerar la BOM para comenzar.

EDITAR: Alternativamente, podría usar un StreamReader para realizar la decodificación. He aquí un ejemplo, que muestra la misma matriz de bytes que se convierte en dos caracteres usando Encoding.GetString o un personaje a través de un StreamReader:

using System; 
using System.IO; 
using System.Text; 

class Test 
{ 
    static void Main() 
    { 
     byte[] withBom = { 0xef, 0xbb, 0xbf, 0x41 }; 
     string viaEncoding = Encoding.UTF8.GetString(withBom); 
     Console.WriteLine(viaEncoding.Length); 

     string viaStreamReader; 
     using (StreamReader reader = new StreamReader 
       (new MemoryStream(withBom), Encoding.UTF8)) 
     { 
      viaStreamReader = reader.ReadToEnd();   
     } 
     Console.WriteLine(viaStreamReader.Length); 
    } 
} 
+0

Tiene razón en que los datos brutos incluyen la lista de materiales. No debería, entonces estoy arreglando esa parte. Una pregunta filosófica de seguimiento: ¿Por qué el método 'String.Equals' toma en cuenta la lista de materiales? ¿Por qué no se ignora simplemente cuando se hace una comparación de cadenas o se trata como metadatos y no como la "carne" de la cadena? – Skrud

+1

@Skrud: Tienes distintas secuencias de caracteres. El método raw String.Equals compara secuencias ordinales, sin más consideraciones. Es posible que algunas de las otras comparaciones de cadenas disponibles (cultura consciente, etc.) pueden ignorar las listas de materiales, no estoy seguro. Dado que es un personaje extraño en algunos aspectos, no estoy realmente convencido de que sea apropiado ignorarlo arbitrariamente. Ponlo de esta manera: la falla de igualdad demostró que tenías algunos datos malos, por lo que el comportamiento te ha llevado a mejorar tu código. Eso es algo bueno, ¿no? –

+1

Absolutamente. Cuál es el punto de prueba en primer lugar. :-) – Skrud

-3

creo que el personaje extra se elimina si TRIM() la cadena decodificada

+0

Esto no funciona ... – wlscaudill

6

Hay es una forma ligeramente más eficiente de hacerlo que creando StreamReader y MemoryStream:

1) Si sabe que siempre hay una lista de materiales

string viaEncoding = Encoding.UTF8.GetString(withBom, 3, withBom.Length - 3); 

2) Si usted no sabe, verificar:

string viaEncoding; 
if (withBom.Length >= 3 && withBom[0] == 0xEF && withBom[1] == 0xBB && withBom[2] == 0xBF) 
    viaEncoding = Encoding.UTF8.GetString(withBom, 3, withBom.Length - 3); 
else 
    viaEncoding = Encoding.UTF8.GetString(withBom); 
Cuestiones relacionadas