对于我的应用程序中的自然排序,我目前在shlwapi.dll中调用一个名为StrCmpLogicalW的函数。我正在考虑尝试在Mono下运行我的应用程序,但当然我不能拥有这个P / Invoke的东西(据我所知)。
是否有可能在某处看到该方法的实现,或者是否有一个好的,干净且高效的C#片段可以做同样的事情?
我的代码目前看起来像这样:
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
public static extern int StrCmpLogicalW(string psz1, string psz2);
}
public class NaturalStringComparer : IComparer<string>
{
private readonly int modifier = 1;
public NaturalStringComparer() : this(false) {}
public NaturalStringComparer(bool descending)
{
if (descending) modifier = -1;
}
public int Compare(string a, string b)
{
return SafeNativeMethods.StrCmpLogicalW(a ?? "", b ?? "") * modifier;
}
}
所以,我正在寻找的是上述类的替代方法,它不使用extern函数。
答案 0 :(得分:10)
我刚刚在C#中实现了自然字符串比较,也许有人可能觉得它很有用:
public class NaturalComparer : IComparer<string>
{
public int Compare(string x, string y)
{
if (x == null && y == null) return 0;
if (x == null) return -1;
if (y == null) return 1;
int lx = x.Length, ly = y.Length;
for (int mx = 0, my = 0; mx < lx && my < ly; mx++, my++)
{
if (char.IsDigit(x[mx]) && char.IsDigit(y[my]))
{
long vx = 0, vy = 0;
for (; mx < lx && char.IsDigit(x[mx]); mx++)
vx = vx * 10 + x[mx] - '0';
for (; my < ly && char.IsDigit(y[my]); my++)
vy = vy * 10 + y[my] - '0';
if (vx != vy)
return vx > vy ? 1 : -1;
}
if (mx < lx && my < ly && x[mx] != y[my])
return x[mx] > y[my] ? 1 : -1;
}
return lx - ly;
}
}
答案 1 :(得分:6)
http://www.interact-sw.co.uk/iangblog/2007/12/13/natural-sorting似乎就是你要找的东西。
(不,没有托管等效于.NET内置的StrCmpLogicalW)
答案 2 :(得分:0)
我使用正则表达式删除特殊字符。然后转换为int。然后我比较了整数。
输入:
List input = new List{ "6.04","6.01","6.03","6#04" };预期产出:
6.01 6.03 6.04 6#04
var output = input.OrderBy(s => s, new NaturalStringComparer()); foreach (var sort in output) { Console.WriteLine(sort); } public struct NaturalStringComparer : IComparer { public int Compare(string x, string y) { if (x == null && y == null) return 0; if (x == null) return -1; if (y == null) return 1; int lx = x.Length, ly = y.Length; int a = int.Parse(System.Text.RegularExpressions.Regex.Replace(x, @"\D+", "")); int b = int.Parse(System.Text.RegularExpressions.Regex.Replace(y, @"\D+", "")); return a.CompareTo(b); } }
答案 3 :(得分:0)
如果您在Windows XP或更高版本上运行,则可以P调用Shell函数StrCmpLogicalW:
public static int StrCmpLogical(String s1, String s2)
{
if (String.IsNullOrEmpty(s1) && !String.IsNullOrEmpty(s2))
return 1; //empty s1 comes after s2
else if (String.IsNullOrEmpty(s2) && !String.IsNullOrEmpty(s1))
return -1; //non-empty string comes before empty
return SafeNativeMethods.StrCmpLogicalW(s1, s2);
}
然后是内部不安全类:
/// <summary>
/// This class suppresses stack walks for unmanaged code permission.
/// (System.Security.SuppressUnmanagedCodeSecurityAttribute is applied to this class.)
/// This class is for methods that are safe for anyone to call.
/// Callers of these methods are not required to perform a full security review to make sure that the
/// usage is secure because the methods are harmless for any caller.
/// </summary>
[SuppressUnmanagedCodeSecurity]
internal static class SafeNativeMethods
{
[DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
internal static extern Int32 StrCmpLogicalW(string psz1, string psz2);
}