Проблема сортировки строк в С#
У меня есть список как
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
Любая идея, почему "a-a" не предшествует "a.a", где "a-" предшествует "a".
Ответы
Ответ 1
Если вы хотите, чтобы ваш сортировка строк основывалась на фактическом значении байта, в отличие от правил, определенных текущей культурой, вы можете сортировать по ординалу:
items.Sort(StringComparer.Ordinal);
Это позволит сделать результаты согласованными во всех культурах (но это приведет к неинтуитивным сортировкам "14", которые предшествуют "9", что может быть или не быть тем, что вы ищете).
Ответ 2
Я подозреваю, что в последнем случае "-" обрабатывается по-другому из-за специфических для культуры настроек (возможно, как "тире", а не "минус" в первых строках). MSDN предупреждает об этом:
Сравнение использует текущую культуру для получения специфических для культуры информации, такой как правила обсадной колонны и алфавитный порядок индивидуальные символы. Например, культура может указать, что некоторые комбинации символов рассматриваются как один символ, или символы верхнего и нижнего регистра сравниваются определенным образом, или что порядок сортировки персонажа зависит от символов которые предшествуют или следуют за ним.
Также см. эту страницу MSDN:
В .NET Framework используются три разных способа сортировки: сортировка слов, сортировка строк и сортировка по порядку. Сортировка Word выполняет чувствительную к культуре сравнение строк. Некоторые неалфанумерные символы могут иметь специальные веса, назначенные им; например, дефис ( "-" ) может имеют очень небольшой вес, назначенный ему, чтобы "курятник" и "кооператив", появляются рядом друг с другом в отсортированном списке. Строковая сортировка аналогична словосочетание, за исключением того, что особых случаев нет; поэтому все nonalphanumeric символы поступают перед всеми буквенно-цифровыми символами. Ordinal sort сравнивает строки, основанные на значениях 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);
Ответ 3
Метод 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