2010-09-15 13 views
8

he añadido una respuesta a esta pregunta aquí: Sorting List<String> in C# que exige un orden natural, que maneja los números incrustados.Escribir un mejor tipo natural, (que la mía)

Mi implementación, sin embargo, es ingenua, y en lugar de todas las publicaciones sobre cómo las aplicaciones no manejan correctamente Unicode asumiendo cosas (¿Turquía prueba a alguien?), Pensé que pediría ayuda escribiendo un mejor implementación. O bien, si hay un método incorporado de .NET, dígame :)

Mi implementación para la respuesta en esa pregunta solo pasa por las cadenas, comparando carácter por carácter, hasta que encuentra un dígito en ambos. Luego extrae dígitos consecutivos de ambas cadenas, lo que puede dar como resultado longitudes variables, las almohadillas son las más cortas con ceros a la izquierda y luego se comparan.

Sin embargo, hay problemas con él.

Por ejemplo, ¿qué pasa si en la cadena x tiene dos puntos de código que juntos forman el carácter È, pero en la otra cadena solo tiene un punto de código, el que es ese carácter.

Mi algoritmo fallaría en los que, ya que podría tratar el punto de código diacrítica como un solo carácter, y compararlo a la dirección de la otra cadena.

¿Alguien me puede guiar hacia cómo manejar esto correctamente? Quiero soporte para especificar un objeto CultureInfo para manejar problemas de idioma, como comparar "ss" con "ß" en Alemania, y cosas similares.

Creo que necesito para obtener mi código para enumerar más de "personajes reales" (no sé el término real aquí) en lugar de puntos de código individuales.

¿Cuál es el enfoque correcto para esto?

Además, si significa "natural", "la forma que los humanos esperan que funcionen", yo añadiría las siguientes cosas a considerar:

  • ¿Qué pasa con las fechas y horas?
  • ¿Qué pasa con los valores de coma flotante?
  • ¿Hay otras secuencias que se consideran "naturales"?
    • ¿hasta dónde puede estirar este? (Eeny, Meeny, miny, moe)

Respuesta

7

Esto ya está disponible en Windows, el shell utiliza el orden natural al organizar los archivos en una ventana del Explorador. La función de comparación que utiliza se exporta y está disponible para cualquier programa, al menos desde Windows 2000. Si bien P/Invoke no es la mejor solución, sí tiene la considerable ventaja de haber sido probado miles de millones de veces en los últimos 10 años impares. Y clasificando cadenas de una manera que el usuario ya esté familiarizado.

Manejar signos diacríticos ya es parte de .NET, el método string.Normalize() se ocupa de ello.

Aquí está un ejemplo de programa que lo utiliza, se ordena adecuadamente las cuerdas como se solicita en el hilo original:

using System; 
using System.Collections.Generic; 
using System.Runtime.InteropServices; 

class Program { 
    static void Main(string[] args) { 
     string[] arr = new string[] { "1", "5", "3", "6", "11", "9", "NUM1", "NUM0" }; 
     Array.Sort(arr, new LogicalComparer()); 
     foreach (string s in arr) Console.WriteLine(s); 
     Console.ReadLine(); 
    } 
} 
class LogicalComparer : IComparer<string> { 
    public int Compare(string x, string y) { 
     return StrCmpLogicalW(x.Normalize(), y.Normalize()); 
    } 
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)] 
    private static extern int StrCmpLogicalW(string s1, string s2); 
} 
+0

Hola hans ... una vez más como siempre ... respuesta increíble ... sólo curiosidad ... ¿cómo llegaste a saber sobre el dll a P/invocar? – Dinesh

+1

Está documentado en el artículo de MSDN para la función, en la parte inferior. –

+0

Lo encontré ... gracias – Dinesh

2

no sé mucho acerca de .NET, pero ya que es también una cuestión algorítmica, aquí están mis dos centavos:

que iba a tratar para dividir la cadena en tokens, probablemente usando expresiones regulares. Luego puede comparar el token de cadenas por token, usando una función de comparación apropiada según el tipo de token.

Más específicamente:

  1. definir expresiones regulares para fechas, números, palabras, ... El último de esos deben ser una expresión de respaldo que coincide con cualquier carácter.
  2. Pruebe cada expresión, la más específica primero, hasta que coincida al principio de ambas cadenas
  3. Extraiga la parte que coincida y compárela utilizando la función de comparación adecuada.
  4. En caso de igualdad, retire el partido desde el comienzo de ambas cadenas y repita desde el paso 2.

Uso de expresiones regulares, también debería ser posible el soporte Unicode, si no se utiliza correctamente, pero [a-zA-Z] clases de caracteres como [:alpha:].

En cuanto a la comparación de las diferentes formas de È, primero puede intentar con normalize la cadena.

+0

Eso es lo que hice en la misma pregunta: ¿http://stackoverflow.com/questions/3716831/sorting-liststring-in-c/3717211 # 3717211. En mi opinión, ofrece una buena separación: primero se descifrarán las diferentes partes del token y se ordenarán en una etapa posterior. – Kobi

+0

Gracias ... ¡Debería haber mirado allí antes de publicar! –

+0

¡realmente no deberías haberlo hecho! ':)' – Kobi

Cuestiones relacionadas