2010-09-15 16 views
8

dodałem odpowiedź na to pytanie tutaj: Sorting List<String> in C# który wzywa do naturalnego porządku sortowania, jeden, który obsługuje osadzone liczb.Pisanie lepszego rodzaju niż naturalne (kopalni)

Moja implementacja jest jednak naiwna, a zamiast wszystkich postów tam, o tym, w jaki sposób aplikacje nie obsługują poprawnie Unicode, zakładając, że (Turcja przetestuje kogokolwiek?), Myślałem, że poproszę o pomoc w napisaniu lepsza realizacja. Lub, jeśli jest wbudowana metoda .NET, proszę mi powiedzieć :)

Moja implementacja odpowiedzi na to pytanie przechodzi przez ciągi, porównując postać po znaku, aż napotka cyfrę w obu. Następnie wyodrębnia kolejne cyfry z obu ciągów, co może skutkować różnymi długościami, padami najkrótszymi z zerami wiodącymi, a następnie porównywać.

Istnieje jednak problemy z nim.

Na przykład, jeśli w ciągu x mają dwa punkty kodowe, które razem tworzą znak È, ale w drugim ciągu masz tylko jeden kod, który jest tą literą.

Mój algorytm nie powiedzie się na nich, ponieważ byłoby traktować diakrytyczną kodowy jako pojedynczego znaku, i porównać go do E z drugiego łańcucha.

Może ktoś poprowadzi mnie ku jak obsługiwać to prawidłowo? Chcę obsługiwać określenie obiektu CultureInfo, aby poradzić sobie z problemami językowymi, takimi jak porównywanie "ss" z "ß" w Niemczech i podobne rzeczy.

Myślę, że potrzebuję dostać mój kod by wyliczyć nad "prawdziwymi znakami" (ja nie znam prawdziwego terminu tutaj) zamiast indywidualnych codepoints.

Co to jest właściwe podejście do tego?

Ponadto, jeśli „naturalny” oznacza „sposób ludzie oczekują go do pracy”, chciałbym dodać następujące rzeczy do rozważenia:

  • Co o terminach i godzinach?
  • Co z wartościami zmiennoprzecinkowymi?
  • Czy istnieją inne sekwencje, które są uważane za "naturalne"?
    • Jak daleko powinno to być rozciągnięte? (Eeny, meeny, miny, Moe)

Odpowiedz

7

Ta opcja jest już dostępna w systemie Windows. Powłoka używa sortowania naturalnego podczas porządkowania plików w oknie Eksploratora. Używana funkcja porównania jest eksportowana i dostępna dla każdego programu, przynajmniej od Windows 2000. O ile P/Invoke nie jest najlepszym rozwiązaniem, ma znaczną przewagę, że testowano go miliardy razy w ciągu ostatnich 10 nieparzystych lat. I sortowanie ciągów znaków w sposób dobrze znany użytkownikowi.

Obsługa znaków diakrytycznych jest już częścią .NET, metoda string.Normalize() zajmuje się tym.

Oto przykładowy program, który go używa, to prawidłowo sortuje ciągi zgodnie z wnioskiem w oryginalnym wątku:

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

Hi hans ... jeszcze raz jak zwykle ... niesamowita odpowiedź ... Po prostu ciekawy ... skąd dowiedziałeś się o bibliotece DLL do P/Invoke into ?? – Dinesh

+1

Jest to udokumentowane w artykule MSDN dla funkcji, na dole. –

+0

Znalazłem ... dzięki – Dinesh

2

nie wiem zbyt wiele o .NET, ale ponieważ jest to również kwestia algorytmiczne, tutaj są moje dwa centy:

bym spróbować podzielić łańcuch na tokeny, prawdopodobnie używając wyrażeń regularnych. Następnie możesz porównać token ciągów za pomocą tokena, używając odpowiedniej funkcji porównania w zależności od typu tokena.

Dokładniej:

  1. Definiowanie wyrażeń regularnych dla dat, liczb, słów ... Ostatni z tych powinny być awaryjna wyrażenie, które dopasowuje dowolny znak.
  2. Wypróbuj każde wyrażenie, najpierw najbardziej szczegółowe, dopóki nie dopasujesz się na początku obu ciągów znaków
  3. Wypakuj część, która pasuje i porównaj ją za pomocą odpowiedniej funkcji porównywania.
  4. W przypadku równości, usuń mecz od początku obu ciągów i powtórz czynności od kroku 2.

Korzystanie z wyrażeń regularnych, powinno być również możliwe wsparcie dla Unicode, jeśli nie używać [a-zA-Z] ale właściwa klasy znaków takie jak [:alpha:].

Jeśli chodzi o porównanie różnych form È, można najpierw spróbować wpisać normalize.

+0

To, co zrobiłem na tym samym pytaniem: http://stackoverflow.com/questions/3716831/sortowanie-liststrowanie-w-c/3717211 # 3717211. Moim zdaniem daje to miły rozdział - najpierw rozgryzamy różne części tokena i sortujemy je na późniejszym etapie. – Kobi

+0

Dzięki ... Powinienem był tam zajrzeć, zanim opublikuję wiadomość! –

+0

naprawdę nie powinieneś był! ':)' – Kobi

Powiązane problemy