C#:shlwapi.dll 中 StrCmpLogicalW 的实现或替代

发布于 2024-08-08 22:43:13 字数 875 浏览 1 评论 0原文

为了在我的应用程序中进行自然排序,我当前在 shlwapi.dll 中 P/Invoke 一个名为 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 函数。

For natural sorting in my application I currently P/Invoke a function called StrCmpLogicalW in shlwapi.dll. I was thinking about trying to run my application under Mono, but then of course I can't have this P/Invoke stuff (as far as I know anyways).

Is it possible to see the implementation of that method somewhere, or is there a good, clean and efficient C# snippet which does the same thing?

My code currently looks like this:

[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;
    }
}

So, what I'm looking for is an alternative to the above class which doesn't use an extern function.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

時窥 2024-08-15 22:43:13

我刚刚在 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;
   }
}

I just implemented natural string comparison in C#, perhaps someone might find it useful:

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;
   }
}
眼睛会笑 2024-08-15 22:43:13

http://www.interact-sw.co.uk/iangblog/2007/ 12/13/natural-sorting 似乎就是您要寻找的。

(不,.NET 中没有内置与 StrCmpLogicalW 等效的托管组件)

http://www.interact-sw.co.uk/iangblog/2007/12/13/natural-sorting seems to be what you're looking for.

(and no, there is no managed equivalent to StrCmpLogicalW built into .NET)

微凉 2024-08-15 22:43:13

我使用正则表达式来删除特殊字符。然后转换为 int。然后我比较了整数。

输入 :

List input = new List{ "6.04","6.01","6.03","6#04" };

Expected Output:

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

I used regular expression to remove special characters. then casting to int. then i compared integers.

input :

List input = new List{ "6.04","6.01","6.03","6#04" };

Expected Output:

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);
        }
    }
暖风昔人 2024-08-15 22:43:13

如果您运行在 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);
}

If you're running on Windows XP or newer, you can PInvoke to the shell function 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);
}

And then the internal unsafe class:

/// <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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文