C#: Implementation of, or alternative to, StrCmpLogicalW in shlwapi.dll

后端 未结 4 1372
一整个雨季
一整个雨季 2020-12-01 17:04

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

相关标签:
4条回答
  • 2020-12-01 17:46

    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);
    }
    
    0 讨论(0)
  • 2020-12-01 17:51

    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)

    0 讨论(0)
  • 2020-12-01 17:55

    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;
       }
    }
    
    0 讨论(0)
  • 2020-12-01 17:55

    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);
            }
        }
    
    0 讨论(0)
提交回复
热议问题