Почему string.Compare, похоже, непоследовательно обрабатывает символы с ударением?

StackOverflow https://stackoverflow.com/questions/1371813

Вопрос

Если я выполню следующий оператор:

string.Compare("mun", "mün", true, CultureInfo.InvariantCulture)

Результат равен '-1', что указывает на то, что 'mun' имеет меньшее числовое значение, чем 'mun'.

Однако, если я выполню это утверждение:

string.Compare("Muntelier, Schweiz", "München, Deutschland", true, CultureInfo.InvariantCulture)

Я получаю "1", указывая, что "Muntelier, Schewiz" должно идти последним.

Это ошибка в сравнении?Или, что более вероятно, существует ли правило, которое я должен учитывать при сортировке строк, содержащих акцентированные


Причина этой проблемы в том, что я сортирую список, а затем выполняю ручной двоичный фильтр, который предназначен для получения каждой строки, начинающейся с 'xxx'.

Раньше я использовал метод Linq 'Where', но теперь мне приходится использовать эту пользовательскую функцию, написанную другим человеком, потому что он говорит, что она работает лучше.

Но пользовательская функция, похоже, не учитывает какие бы то ни было правила 'unicode' .NET имеет.Поэтому, если я скажу ему фильтровать по 'mun', он не найдет никаких элементов, даже если в списке есть элементы, начинающиеся с 'mun'.

По-видимому, это происходит из-за непоследовательного порядка символов с ударением, в зависимости от того, какие символы идут после символа с ударением.


Хорошо, я думаю, что я устранил проблему.

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

Это было полезно?

Решение

В действии действует алгоритм разрыва связей, см. http://unicode.org/reports/tr10/

Чтобы устранить сложности сортировки, зависящей от языка, используется многоуровневый алгоритм сравнения .При сравнении двух слов, например , наиболее важной особенностью является базовый символ:например, разница между буквами А и Б.Различия в ударениях обычно игнорируются, если есть какие-либо различия в базовых буквах.Различия в регистре (верхний и нижний регистры), обычно игнорируются, если есть какие-либо различия в основе или ударениях.Пунктуация изменчива.В некоторых ситуациях знак препинания рассматривается как базовый символ.В других ситуациях его следует игнорировать при наличии какой-либо основы, ударения или падежа различия.Также может существовать заключительный, решающий уровень, при котором, если вообще нет других различий в строке используется (нормализованный) код порядок точек.

Итак, "Munt..." и "Münc..." различаются по алфавиту и сортируются на основе "t" и "c".

Принимая во внимание, что "mun" и "mün" в алфавитном порядке совпадают ("u" эквивалентно "ü" в утраченных языках), поэтому сравниваются коды символов

Другие советы

Похоже, что символ с ударением используется только в своего рода ситуации "тай-брейка" - другими словами, если строки в остальном равны.

Вот несколько примеров кода для демонстрации:

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

Я подозреваю, что это правильно в соответствии с различными сложными правилами Юникода, но я недостаточно о них знаю.

Что касается того, нужно ли вам принимать это во внимание...Я бы этого не ожидал.Что вы делаете такого, что сбито с толку этим?

Насколько я понимаю, это все еще несколько последовательно.При сравнении с использованием 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);

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top