8

我在这里添加了对这个问题的答案:在 C#中排序List<String>,它需要自然的排序顺序,即处理嵌入数字的顺序。

然而,我的实现是幼稚的,代替所有关于应用程序如何通过假设事情(土耳其测试任何人?)来正确处理 Unicode 的帖子,我想我会寻求帮助来编写更好的实现。或者,如果有.NET的内置方法,请告诉我:)

我对该问题的答案的实现只是遍历字符串,逐个字符进行比较,直到在两者中都遇到一个数字。然后它从两个字符串中提取连续的数字,这可能导致长度不同,用前导零填充最短的数字,然后进行比较。

但是,它存在问题。

例如,如果您在字符串 x 中有两个代码点,它们一起构成字符 È,但在另一个字符串中您只有一个代码点,即那个字符。

我的算法会在这些问题上失败,因为它将变音符号代码点视为单个字符,并将其与另一个字符串中的 È 进行比较。

谁能指导我如何正确处理这个问题?我希望支持指定一个CultureInfo对象来处理语言问题,比如在德国比较“ss”和“ß”,以及类似的事情。

我想我需要让我的代码枚举“真实字符”(我不知道这里的真实术语)而不是单个代码点。

什么是正确的方法?

另外,如果“自然”意味着“人类期望它的工作方式”,我会添加以下内容来思考:

  • 日期和时间呢?
  • 浮点值呢?
  • 还有其他被认为是“自然”的序列吗?
    • 这应该延伸到什么程度?(Eeny,meeny,miny,萌)
4

2 回答 2

8

这在 Windows 中已经可用,当在资源管理器窗口中排列文件时,shell 使用自然排序顺序。它使用的比较功能可以导出并可供任何程序使用,至少从 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);
}
于 2010-09-15T13:12:50.877 回答
2

我对 .NET 了解不多,但由于这也是一个算法问题,所以这里是我的两分钱:

我会尝试将字符串拆分为标记,可能使用正则表达式。然后,您可以根据令牌类型使用适当的比较函数逐个令牌比较字符串。

进一步来说:

  1. 为日期、数字、单词等定义正则表达式……最后一个应该是匹配任何字符的后备表达式。
  2. 尝试每个表达式,首先尝试最具体的表达式,直到一个匹配两个字符串的开头
  3. 提取匹配的部分并使用适当的比较函数进行比较。
  4. 如果相等,则从两个字符串的开头删除匹配项,然后从步骤 2 开始重复。

使用正则表达式,也应该可以支持 unicode,如果你不使用[a-zA-Z]正确的字符类,比如[:alpha:].

至于È不同形式的比较,可以先尝试对字符串进行归一化处理。

于 2010-09-15T12:01:28.023 回答