C#:在 shlwapi.dll 中实现或替代 StrCmpLogicalW
Posted
技术标签:
【中文标题】C#:在 shlwapi.dll 中实现或替代 StrCmpLogicalW【英文标题】:C#: Implementation of, or alternative to, StrCmpLogicalW in shlwapi.dll 【发布时间】:2009-10-21 16:00:53 【问题描述】:为了在我的应用程序中进行自然排序,我目前在 shlwapi.dll 中 P/Invoke 一个名为 StrCmpLogicalW 的函数。我正在考虑尝试在 Mono 下运行我的应用程序,但是我当然不能拥有这个 P/Invoke 东西(据我所知)。
是否有可能在某处看到该方法的实现,或者是否有一个好的、干净和高效的 C# sn-p 可以做同样的事情?
我的代码目前如下所示:
[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;
所以,我正在寻找的是不使用外部函数的上述类的替代方案。
【问题讨论】:
我刚刚在 C# 中找到了这个blog post on natural sorting。这有什么用吗?回应您的评论 - 我自己并没有详细分析它,它看起来很有希望。那里肯定还有其他自然排序的 c# 实现,也许您只需要找到一个并对其进行概要分析? 实际上刚读完:P 它似乎做了我认为应该做的事情,但它似乎也很低效......不过我真的不知道......呵呵。 我认为没有原生的 .NET 方式。 没有与 StrCmpLogicalW 等效的 .net 框架。 write your own 或 pinvoke。 【参考方案1】:我刚刚在 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;
【讨论】:
它不完整,如果你有 ex1、ex-3、ex2,那么 ex-3 将成为最后一个。 pinvoke windows function 自然排序算法对它的explorer很喜欢。 最后一行应该是return lx - mx - (ly - my)
。此外,char.IsDigit
可能会为 '0'..'9' 之外的其他 Unicode 数字返回 true
溢出也有问题
@HermanVanDerBlom StrCmpLogicalW
在 Windows shell 文件资源管理器中工作的原因是因为它是来自 Windows Shell API shlwapi
的函数。可能是因为它来自 Shell,它在其他 API 中不存在,虽然 Windows Shell 被移植到 ARM,但它并没有包含在他们较新的 Windows Store App 中。【参考方案2】:
http://www.interact-sw.co.uk/iangblog/2007/12/13/natural-sorting 似乎就是您要找的东西。
(不,没有托管等效于 .NET 中内置的 StrCmpLogicalW)
【讨论】:
博文的解决方案不正确,因为它对 name1、name 10、name 9 进行排序。【参考方案3】:我使用正则表达式来删除特殊字符。然后转换为 int。然后我比较了整数。
输入:
列表输入 = 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 排序) Console.WriteLine(排序); 公共结构 NaturalStringComparer : IComparer 公共 int 比较(字符串 x,字符串 y) if (x == null && y == null) 返回 0; 如果(x == null)返回-1; 如果(y == null)返回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+", "")); 返回 a.CompareTo(b);【讨论】:
【参考方案4】:如果您在 Windows XP 或更新版本上运行,您可以 PInvoke 到 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);
【讨论】:
注意 ARM 设备不支持 StrCmpLogicalW。因此,如果您通过 Windows 应用商店部署到 ARM,这将不会成功。以上是关于C#:在 shlwapi.dll 中实现或替代 StrCmpLogicalW的主要内容,如果未能解决你的问题,请参考以下文章
尝试迁移 postgreSQL 时出现或接近“WITH ORDINALITY”错误的语法错误