Почему 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);

дает желаемый результат.

В любом случае, я думаю, вам будет лучше основать вашу сортировку на определенной культуре, такой как текущая культура пользователя (если это возможно).