写一个更好的自然类型(比我的)

时间:2010-09-15 11:26:46

标签: .net unicode natural-sort codepoint

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

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

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

然而,它存在问题。

例如,如果你在字符串x中有两个代码点一起构成字符È,但在另一个字符串中你只有一个代码点,那就是那个字符。

我的算法会失败,因为它会将变音符号码视为单个字符,并将其与其他字符串中的È进行比较。

任何人都可以指导我如何妥善处理这个问题吗?我希望支持指定一个CultureInfo对象来处理语言问题,比如在德国比较“ss”和“ß”,以及类似的东西。

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

对此有什么正确的解决方法?

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

  • 日期和时间怎么样?
  • 浮点值怎么样?
  • 是否有其他被认为是“天然”的序列?
    • 这应该延伸多远? (Eeny,meeny,miny,moe)

2 个答案:

答案 0 :(得分:7)

这在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);
}

答案 1 :(得分:2)

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

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

更具体地说:

  1. 为日期,数字,单词等定义正则表达式...最后一个应该是与任何字符匹配的后备表达式。
  2. 尝试每个表达式,最具体的是第一个,直到一个表达式在两个字符串的开头匹配
  3. 使用适当的比较函数提取匹配的部分并进行比较。
  4. 如果相等,请从两个字符串的开头删除匹配项,然后从步骤2开始重复。
  5. 使用正则表达式,如果你不使用[a-zA-Z]但是正确的字符类如[:alpha:],也应该可以支持unicode。

    对于不同形式的È的比较,你可以先尝试normalize字符串。