Проблема сортировки строк в C # - PullRequest
14 голосов
/ 20 февраля 2012

У меня есть список вроде этого

    List<string> items = new List<string>();
    items.Add("-");
    items.Add(".");
    items.Add("a-");
    items.Add("a.");
    items.Add("a-a");
    items.Add("a.a");

    items.Sort();

    string output = string.Empty;
    foreach (string s in items)
    {
        output += s + Environment.NewLine;
    }

MessageBox.Show(output);

Выход возвращается как

-
.
a-
a.
a.a
a-a

, где я ожидаю результатов, как

-
.
a-
a.
a-a
a.a

Любая идея, почему «а-а» не предшествует «а.а», а «а-» предшествует «а».

Ответы [ 3 ]

17 голосов
/ 20 февраля 2012

Я подозреваю, что в последнем случае «-» обрабатывается по-другому из-за специфических для культуры настроек (возможно, как «тире», а не «минус» в первых строках). MSDN предупреждает об этом:

Сравнение использует текущую культуру для получения конкретной культуры информация, такая как правила кожуха и алфавитный порядок отдельные персонажи. Например, культура может указать, что определенные комбинации символов должны рассматриваться как один символ, или прописные и строчные буквы сравниваются определенным образом, или что порядок сортировки символа зависит от символов которые предшествуют или следуют за ним.

Также см. В эту страницу MSDN :

.NET Framework использует три различных способа сортировки: сортировка слов, сортировка строк и порядковая сортировка. Сортировка слов выполняет чувствительный к культуре сравнение строк. Некоторые не буквенно-цифровые символы могут иметь им присвоены специальные веса; например, дефис ("-") может иметь очень маленький вес, назначенный ему так, чтобы "кооператив" и "кооператив" появляются рядом друг с другом в отсортированном списке. Сортировка строк похожа на сортировка слов, за исключением того, что особых случаев нет; поэтому все не буквенно-цифровые символы располагаются перед всеми буквенно-цифровыми символами. Порядковая сортировка сравнивает строки на основе значений Unicode каждого элемент строки.

Итак, дефис получает специальную обработку в режиме сортировки по умолчанию, чтобы сделать сортировку слов более «естественной».

Вы можете получить "нормальную" порядковую сортировку, если специально ее включите:

     Console.WriteLine(string.Compare("a.", "a-"));                  //1
     Console.WriteLine(string.Compare("a.a", "a-a"));                //-1

     Console.WriteLine(string.Compare("a.", "a-", StringComparison.Ordinal));    //1
     Console.WriteLine(string.Compare("a.a", "a-a", StringComparison.Ordinal));  //1

Для сортировки исходной коллекции с использованием порядкового сравнения используйте:

     items.Sort(StringComparer.Ordinal);
4 голосов
/ 20 февраля 2012

Если вы хотите, чтобы сортировка строк основывалась на фактическом значении байта, а не на правилах, определенных текущей культурой, вы можете отсортировать по Ординалу:

items.Sort(StringComparer.Ordinal);

Это сделает результаты согласованными во всех культурах (но это приведет к неинтуитивной сортировке «14», предшествующих «9», что может или не может быть тем, что вы ищете).

4 голосов
/ 20 февраля 2012

Метод Sort класса List<> основан на стандартном string компараторе .NET Framework, который фактически является экземпляром текущего CultureInfo Thread.

.

CultureInfo указывает алфавитный порядок символов, и кажется, что по умолчанию используется порядок, отличный от того, который вы ожидаете.

При сортировке вы можете указать конкретный CultureInfo, который, как вы знаете, будет соответствовать вашим требованиям сортировки, образец (немецкая культура):

var sortCulture = new CultureInfo("de-DE");
items.Sort(sortCulture);

Более подробную информацию можно найти здесь:
http://msdn.microsoft.com/en-us/library/b0zbh7b6.aspx
http://msdn.microsoft.com/de-de/library/system.stringcomparer.aspx

...