2009-09-03 8 views
14

Si ejecuta la siguiente instrucción:¿Por qué string.Compare parece manejar caracteres acentuados de manera incoherente?

string.Compare("mun", "mün", true, CultureInfo.InvariantCulture) 

El resultado es '-1', lo que indica que 'mun' tiene un valor numérico más bajo que 'Mun.

Sin embargo, si ejecuto esta declaración:

string.Compare("Muntelier, Schweiz", "München, Deutschland", true, CultureInfo.InvariantCulture) 

recibo el mensaje '1', indicando que 'Muntelier, Schewiz' debe ir pasado.

¿Esto es un error en la comparación? O, más probablemente, es que hay una regla debería de tomar en cuenta al ordenar cadenas que contienen acentuado


La razón de que esto es un problema es que estoy ordenar una lista y luego hacer un filtro binario manual que ha significado para obtener cada cadena que comienza con 'xxx'.

Anteriormente estaba usando el método Linq 'Where', pero ahora tengo que usar esta función personalizada escrita por otra persona, porque dice que tiene un mejor rendimiento.

Pero la función personalizada no parece tener en cuenta las reglas 'Unicode' que tiene .NET. Entonces, si le digo que filtre por 'mün', no encuentra ningún elemento, aunque hay elementos en la lista que comienzan con 'mun'.

Esto parece deberse al ordenamiento incoherente de los caracteres acentuados, dependiendo de qué caracteres vayan después del carácter acentuado.


Bien, creo que he solucionado el problema.

antes del filtro, hago una especie en base a los primeros n cartas de cada cadena, donde n es la longitud de la cadena de búsqueda.

+0

Es momentos como este que me gustaría que el .NET Framework era de código abierto, así que podría pasar al modo de depuración y descubrir exactamente qué está haciendo. – Jonathan

+4

@jonathanconway: Es posible recorrer el código fuente de la biblioteca de la clase base, ver http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net- framework-source-code.aspx –

+0

@divo Gracias por la referencia. ¡Nunca me di cuenta que esto era posible! – Jonathan

Respuesta

22

No es un algoritmo de desempate en el trabajo, ver http://unicode.org/reports/tr10/

Para hacer frente a las complejidades de clasificación sensible al lenguaje, un algoritmo de comparación de niveles múltiples es empleado. En la comparación de dos palabras, para ejemplo, la característica más importante es el carácter de base: como la diferencia entre una A y una B. Diferencias de acento son normalmente ignorados , si hay algunas diferencias en las letras básicas. Las diferencias entre mayúsculas y minúsculas (mayúsculas y minúsculas), son generalmente ignoradas, si hay alguna diferencia en la base o los acentos. La puntuación es variable. En algunas situaciones , un carácter de puntuación es tratado como un carácter base. En otras situaciones, se debe ignorar si hay alguna base, acento o caso diferencias. También puede haber un final, nivel de desempate, por el cual si no hay otras diferencias en absoluto en la cadena, se usa el orden de punto (normalizado) .

Por lo tanto, "Munt ..." y "Münc ..." son alfabéticamente diferentes y se ordenan según la "t" y la "c".

Considerando que, "mun" y "Mün" son alfabéticamente la misma ("u" equivelent de "U" en lenguas perdidas) por lo que los códigos de caracteres se comparan

6

Parece que el carácter acentuado solo se usa en una especie de situación de "desempate", es decir, si las cuerdas son iguales.

Aquí hay un código de ejemplo para demostrar: (. He intentado añadir un espacio después de la "n", así, para ver si se ha hecho en los límites de palabra - no lo es)

using System; 
using System.Globalization; 

class Test 
{ 
    static void Main() 
    { 
     Compare("mun", "mün"); 
     Compare("muna", "münb"); 
     Compare("munb", "müna"); 
    } 

    static void Compare(string x, string y) 
    { 
     int result = string.Compare(x, y, true, 
            CultureInfo.InvariantCulture)); 

     Console.WriteLine("{0}; {1}; {2}", x, y, result); 
    } 
} 

resultados:

mun; mün; -1 
muna; münb; -1 
munb; müna; 1 

sospecho que esto es correcto por varias reglas complicadas Unicode - pero no sé lo suficiente sobre ellos.

En cuanto a si necesita tener esto en cuenta ... No me lo esperaba. ¿Qué estás haciendo que arroja esto?

4

Según tengo entendido, sigue siendo algo consistente. Al comparar usando CultureInfo.InvariantCulture, el carácter umlaut ü se trata como el carácter sin acentos u.

Como las cadenas en su primer ejemplo obviamente no son iguales, el resultado no será 0 sino -1 (que parece ser un valor predeterminado). En el segundo ejemplo Muntelier va último porque t sigue c en el alfabeto.

no pude encontrar ninguna documentación de MSDN claro en explicar estas reglas, pero me encontré con que

string.Compare("mun", "mün", CultureInfo.InvariantCulture, 
    CompareOptions.StringSort); 

y

string.Compare("Muntelier, Schweiz", "München, Deutschland", 
    CultureInfo.InvariantCulture, CompareOptions.StringSort); 

da el resultado deseado.

De todos modos, creo que sería mejor que basas tu clasificación en una cultura específica, como la cultura del usuario actual (si es posible).

+0

'CompareOptions.Ordinal' también podría ser una opción. Con esta opción, las cadenas se compararán en función de los valores Unicode. Consulte http://msdn.microsoft.com/en-us/library/system.globalization.compareoptions.aspx. –

Cuestiones relacionadas