Написание лучшего натурального вида (чем у меня) - PullRequest
8 голосов
/ 15 сентября 2010

Я добавил ответ на этот вопрос здесь: Сортировка List<String> в C # , которая требует естественного порядка сортировки, который обрабатывает вложенные числа.

Моя реализация, однако, наивна, и вместо всех постов о том, как приложения не обрабатывают Unicode правильно, предполагая что-то (Турция проверяет кого-нибудь?), Я подумал, что я бы попросил помочь написать лучшее реализация. Или, если есть встроенный метод .NET, скажите, пожалуйста:)

Моя реализация ответа на этот вопрос просто проходит по строкам, сравнивая символ за символом, пока не встретит цифру в обоих. Затем он извлекает последовательные цифры из обеих строк, что может привести к изменению длины, дополняет самые короткие начальные нули, а затем сравнивает.

Однако с этим есть проблемы.

Например, что если у вас в строке x есть две кодовые точки, которые вместе составляют символ È, но в другой строке у вас есть только одна кодовая точка, та, которая является этим символом.

Мой алгоритм не сработает, поскольку он будет обрабатывать диакритическую кодовую точку как один символ и сравнивать ее с È из другой строки.

Может кто-нибудь подсказать мне, как правильно с этим справиться? Мне нужна поддержка для указания объекта CultureInfo для решения языковых проблем, таких как сравнение «ss» с «ß» в Германии и тому подобное.

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

Какой правильный подход к этому?

Кроме того, если «естественный» означает «то, как люди ожидают, что он будет работать», я бы добавил следующие соображения:

  • А как насчет дат и времени?
  • А как насчет значений с плавающей запятой?
  • Существуют ли другие последовательности, которые считаются "естественными"?
    • Как далеко это должно быть растянуто? (Эни, мини, мин, мо)

Ответы [ 2 ]

7 голосов
/ 15 сентября 2010

Это уже доступно в Windows, оболочка использует естественный порядок сортировки при расположении файлов в окне проводника.Используемая функция сравнения экспортируется и доступна для любой программы, по крайней мере, начиная с Windows 2000. Хотя P / Invoke не является лучшим решением, у него есть значительное преимущество: его тестировали миллиарды раз за последние 10 с лишним лет.И сортировка строк таким образом, что пользователь уже хорошо знаком.

Обработка диакритических знаков уже является частью .NET, метод string.Normalize () позаботится об этом.

ВотВ примере программы, в которой он используется, он правильно сортирует строки в соответствии с запросом исходного потока:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

class Program {
    static void Main(string[] args) {
        string[] arr = new string[] { "1", "5", "3", "6", "11", "9", "NUM1", "NUM0" };
        Array.Sort(arr, new LogicalComparer());
        foreach (string s in arr) Console.WriteLine(s);
        Console.ReadLine();
    }
}
class LogicalComparer : IComparer<string> {
    public int Compare(string x, string y) {
        return StrCmpLogicalW(x.Normalize(), y.Normalize());
    }
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
    private static extern int StrCmpLogicalW(string s1, string s2);
}
2 голосов
/ 15 сентября 2010

Я не очень разбираюсь в .NET, но так как это также алгоритмический вопрос, вот мои два цента:

Я бы попытался разбить строку на токены, возможно, используя регулярные выражения. Затем вы можете сравнить токен строк по токену, используя соответствующую функцию сравнения в зависимости от типа токена.

Более конкретно:

  1. Определите регулярные выражения для дат, чисел, слов, ... Последнее из них должно быть резервным выражением, которое соответствует любому символу.
  2. Попробуйте каждое выражение, сначала самое конкретное, до совпадения в начале обеих строк
  3. Извлеките соответствующую часть и сравните ее, используя соответствующую функцию сравнения.
  4. В случае равенства удалите совпадение из начала обеих строк и повторите с шага 2.

Используя регулярные выражения, также должна быть возможность поддержки юникода, если вы не используете [a-zA-Z], но подходящие классы символов, такие как [:alpha:].

Что касается сравнения различных форм È, вы можете попробовать нормализовать строку вначале.

...