visual minusculas mayusculas ejemplos comparar cadenas c# .net string sorting string-comparison

c# - minusculas - ¿Por qué el comparador de cadenas por defecto no mantiene la consistencia transitiva?



string.compare c# (1)

Discusión de Microsoft Connect Aquí hay algunos códigos para la solución alternativa:

static int CompareStringUsingSortKey(string s1, string s2) { SortKey sk1 = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(s1); SortKey sk2 = CultureInfo.InvariantCulture.CompareInfo.GetSortKey(s2); return SortKey.Compare(sk1, sk2); }

Sé que este problema se ha notado antes , más o menos concisamente, pero sigo creando este nuevo hilo porque volví a encontrar con el problema al escribir una prueba unitaria.

La comparación de cadenas por defecto (que es la comparación de mayúsculas y minúsculas dependiente de cultura que obtenemos con string.CompareTo(string) , Comparer<string>.Default , StringComparer.CurrentCulture , string.Compare(string, string) y otras) viola transitividad cuando las cadenas contienen guiones (o signos menos, estoy hablando de caracteres simples U + 002D).

Aquí hay una reproducción simple:

static void Main() { const string a = "fk-"; const string b = "-fk"; const string c = "Fk"; Console.WriteLine(a.CompareTo(b)); // "-1" Console.WriteLine(b.CompareTo(c)); // "-1" Console.WriteLine(a.CompareTo(c)); // "1" var listX = new List<string> { a, b, c, }; var listY = new List<string> { c, a, b, }; var listZ = new List<string> { b, c, a, }; listX.Sort(); listY.Sort(); listZ.Sort(); Console.WriteLine(listX.SequenceEqual(listY)); // "False" Console.WriteLine(listY.SequenceEqual(listZ)); // "False" Console.WriteLine(listX.SequenceEqual(listZ)); // "False" }

En la parte superior vemos cómo falla la transitividad. a es menor que b , b es menor que c , pero a no es menor que c .

Esto va en contra del comportamiento documentado de la intercalación Unicode que establece que:

... para cualquier cadena A, B y C, si A <B y B <C, entonces A <C.

Ahora ordenar una lista con a , c es exactamente como tratar de clasificar las manos de "Rock", "Papel" y "Tijeras" en el famoso juego intransitivo. Una tarea imposible.

La última parte de mi ejemplo de código anterior muestra que el resultado de la clasificación depende del orden inicial de los elementos (y no hay dos elementos en la lista que comparen "igual" ( 0 )).

La listX.OrderBy(x => x) de Linq listX.OrderBy(x => x) también se ve afectada, por supuesto. Esto debería ser un tipo estable, pero obtienes resultados extraños cuando ordenes una colección que contiene a , c junto con otras cadenas.

Intenté esto con todos los CultureInfo en mi máquina (ya que este es un tipo dependiente de la cultura), incluida la "cultura invariante", y todos y cada uno tienen el mismo problema. Intenté esto con .NET 4.5.1 runtime, pero creo que las versiones anteriores tienen el mismo error.

Conclusión: al ordenar cadenas en .NET con el comparador predeterminado, los resultados son impredecibles si algunas cadenas contienen guiones.

¿Qué cambios se introdujeron en .NET 4.0 que causaron este comportamiento?

Ya se ha observado que este comportamiento no es uniforme en las diferentes versiones de la plataforma: en .NET 3.5, las cadenas con guiones se pueden clasificar de forma fiable. En todas las versiones del marco, al llamar a System.Globalization.CultureInfo.CurrentCulture.CompareInfo.GetSortKey proporciona DeyData exclusivo para estas cadenas, entonces, ¿por qué no están ordenadas correctamente?