Почему string.Compare, по-видимому, обрабатывает акцентированные символы непоследовательно?
Если я выполню следующий оператор:
string.Compare("mun", "mün", true, CultureInfo.InvariantCulture)
Результат равен "-1", что указывает, что "mun" имеет меньшее числовое значение, чем "mün".
Однако, если я выполню это утверждение:
string.Compare("Muntelier, Schweiz", "München, Deutschland", true, CultureInfo.InvariantCulture)
Я получаю "1", указывая, что "Muntelier, Schewiz" должен длиться последним.
Это ошибка в сравнении? Или, скорее, есть правило, которое я должен учитывать при сортировке строк, содержащих акцентированные
Причина в том, что это проблема, я сортирую список, а затем выполняю ручной двоичный фильтр, который означает, что каждая строка начинается с "xxx".
Раньше я использовал метод Linq 'Where', но теперь я должен использовать эту настраиваемую функцию, написанную другим человеком, потому что он говорит, что она работает лучше.
Но пользовательская функция, похоже, не учитывает любые правила unicode.NET. Поэтому, если я скажу, что он фильтрует "mün", он не находит никаких элементов, даже если в списке есть элементы, начинающиеся с "mun".
Это, по-видимому, из-за несогласованного упорядочения акцентированных символов, в зависимости от того, какие символы идут после акцентированного символа.
Хорошо, я думаю, что исправил проблему.
Перед фильтром я делаю сортировку на основе первых n букв каждой строки, где n - длина строки поиска.
Ответы
Ответ 1
На работе существует алгоритм тай-брейка, см. http://unicode.org/reports/tr10/
Чтобы устранить сложности чувствительная к языку сортировка, многоуровневый алгоритм сравнения занятый. Сравнивая два слова, для Например, наиболее важной особенностью является базовый символ: например, разница между A и B. Акцентные различия обычно игнорируются, если есть какие-либо различия в базовых буквах. Случайные различия (в верхнем и нижнем регистре), обычно игнорируются, если есть различия в базе или акцентах. Пунктуация является переменной. В некоторых ситуациях символ пунктуации как базовый персонаж. В в других ситуациях его следует игнорировать если есть какая-либо база, акцент или случай различия. Также может быть окончательный, разрывный уровень, при котором, если нет других различий вообще в строке, (нормализованный) код используется точечный порядок.
Итак, "Munt..." и "Münc..." отличаются в алфавитном порядке и сортируются на основе "t" и "c".
В то время как "mun" и "mün" в алфавитном порядке одинаковы ( "u" равнозначны "ü" в потерянных языках), поэтому коды символов сравниваются
Ответ 2
Похоже, что акцентированный символ используется только в какой-то ситуации "тай-брейка" - другими словами, если строки в противном случае равны.
Вот пример кода для демонстрации:
using System;
using System.Globalization;
class Test
{
static void Main()
{
Compare("mun", "mün");
Compare("muna", "münb");
Compare("munb", "müna");
}
static void Compare(string x, string y)
{
int result = string.Compare(x, y, true,
CultureInfo.InvariantCulture));
Console.WriteLine("{0}; {1}; {2}", x, y, result);
}
}
(Я попытался добавить пробел после "n", чтобы посмотреть, было ли это сделано на границах слов - это не так.)
Результаты:
mun; mün; -1
muna; münb; -1
munb; müna; 1
Я подозреваю, что это правильно по различным сложным правилам Unicode, но я не знаю о них достаточно.
Относительно того, нужно ли это учитывать... Я бы так не ожидал. Что вы делаете, что брошено этим?
Ответ 3
Как я понимаю, он все еще несколько последователен. При сравнении с использованием CultureInfo.InvariantCulture
символ умлаута ü
обрабатывается как неадресный символ u
.
Поскольку строки в вашем первом примере, очевидно, не равны, результат будет не 0, а -1 (что, по-видимому, является значением по умолчанию). Во втором примере Muntelier идет последним, потому что t следует c в алфавите.
Я не смог найти четкую документацию в MSDN, объясняющую эти правила, но обнаружил, что
string.Compare("mun", "mün", CultureInfo.InvariantCulture,
CompareOptions.StringSort);
и
string.Compare("Muntelier, Schweiz", "München, Deutschland",
CultureInfo.InvariantCulture, CompareOptions.StringSort);
дает желаемый результат.
В любом случае, я думаю, вам будет лучше основать вашу сортировку на определенной культуре, такой как текущая культура пользователя (если это возможно).