Почему "-less" сортируется после "привет", а не перед ним? - PullRequest
6 голосов
/ 10 сентября 2010

Я вижу очень странное поведение сортировки с использованием CaseInsensitiveComparer.DefaultInvariant. Слова, начинающиеся с начального дефиса "-", в конечном итоге сортируются так, как будто дефиса не было, а не перед фактическими буквами, что и происходит с другими пунктуациями.

Итак, учитывая {"hello", ".net", "-less"}, я получаю {".net", "hello", "-less"} вместо ожидаемого {"-less", " .net "," hello "}.

Или, сформулированный как контрольный пример:

[TestMethod]
public void TestMethod1()
{
    var rg = new String[] { 
        "x", "z", "y", "-less", ".net", "- more", "a", "b"
    };

    Array.Sort(rg, CaseInsensitiveComparer.DefaultInvariant);

    Assert.AreEqual(
        "- more,-less,.net,a,b,x,y,z", 
        String.Join(",", rg)
    );
}

... что не получается так:

Assert.AreEqual failed. 
Expected:<- more,-less,.net,a,b,x,y,z>. 
Actual:  <- more,.net,a,b,-less,x,y,z>.

Есть идеи, что происходит?

Edit:

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

Array.Sort(rg, (a, b) => String.CompareOrdinal(a, b));

Ответы [ 4 ]

11 голосов
/ 10 сентября 2010

Процедуры сравнения используют CultureInfo.InvariantCulture для определения порядка сортировки и правил оболочки. Сравнение строк может иметь разные результаты в зависимости от культуры. Для получения дополнительной информации о сравнениях, характерных для культуры, см. Пространство имен System.Globalization и Кодирование и локализация. Отсюда.

Интересная часть:

Сортировка слов выполняет чувствительное к культуре сравнение строк, в которых некоторым не буквенно-цифровым символам Юникода могут быть назначены специальные веса. Например, дефису (-) может быть присвоен очень маленький вес, чтобы «кооператив» и «кооператив» появлялись рядом друг с другом в отсортированном списке. Отсюда.

3 голосов
/ 10 сентября 2010

Чтобы отсортировать строки так, как вам нужно, вы должны создать класс сравнения, который сравнивает строки, используя класс Compareinfo . Этот класс позволяет указывать различные методы сравнения, наиболее подходящий для вас - OrdinalIgnoreCase.

Из MSDN:

Игнорируемые значения поиска

Операции сравнения, такие как выполняется IndexOf или LastIndexOf методов, может дать неожиданные результаты, если значение поиск игнорируется. Поиск значение игнорируется, если оно пустое строка (""), символ или строка состоящий из символов, имеющих код точки, которые не рассматриваются в операция из-за сравнения параметры или значение с кодовыми точками которые не имеют лингвистического значения. Если значение поиска для IndexOf Метод является пустой строкой, для Например, возвращаемое значение равно нулю.

Примечание
По возможности приложение следует использовать методы сравнения строк которые принимают значение CompareOptions для укажите вид сравнения ожидается. Как общее правило, сравнение с пользователем лучше обслуживается с помощью лингвистического варианты (используя текущую культуру), в то время как сравнения безопасности должны указать Ordinal или OrdinalIgnoreCase.specify Ordinal или OrdinalIgnoreCase.

Я изменил ваш тестовый пример, и этот тест выполняется правильно:

public class MyComparer:Comparer<string>
{
    private readonly CompareInfo compareInfo;

    public MyComparer()
    {
        compareInfo = CompareInfo.GetCompareInfo(CultureInfo.InvariantCulture.Name);
    }

    public override int Compare(string x, string y)
    {
        return compareInfo.Compare(x, y, CompareOptions.OrdinalIgnoreCase);
    }
}

public class Class1
{
    [Test]
    public void TestMethod1()
    {
        var rg = new String[] { 
    "x", "z", "y", "-less", ".net", "- more", "a", "b"
};

        Array.Sort(rg, new MyComparer());

        Assert.AreEqual(
            "- more,-less,.net,a,b,x,y,z",
            String.Join(",", rg)
        );


    }
}
2 голосов
/ 10 сентября 2010

Мое предположение могло бы состоять в том, что черта немедленно перед тем, как письмо игнорируется, в целях сортировки.Когда вы сортируете список слов, вы бы хотели, чтобы слова «межнациональный» и «международный» были рядом друг с другом, не так ли?С другой стороны, тире считается значительным.

0 голосов
/ 10 сентября 2010

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

http://msdn.microsoft.com/en-us/library/a7zyyk0c.aspx

В вашем примере, «h» (U + 0048) перед «чертой» (U + 2013), поэтому «привет» будет появляться перед «-less». "" (U + 002E) перед обоими, поэтому «.net» появляется первым.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...