C #: реализация или альтернатива StrCmpLogicalW в shlwapi.dll - PullRequest
9 голосов
/ 21 октября 2009

Для естественной сортировки в моем приложении я в настоящее время выполняю функцию P / Invoke под названием StrCmpLogicalW в shlwapi.dll. Я думал о том, чтобы попытаться запустить мое приложение под 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.

Ответы [ 4 ]

10 голосов
/ 13 апреля 2011

Я только что реализовал естественное сравнение строк в 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;
   }
}
6 голосов
/ 09 января 2012

http://www.interact -sw.co.uk / iangblog / 2007/12/13 / Natural-sorting , кажется, то, что вы ищете.

(и нет, управляемый эквивалент StrCmpLogicalW, встроенного в .NET отсутствует)

0 голосов
/ 21 февраля 2019

Если вы работаете в Windows XP или новее, вы можете вызвать PInvoke для функции оболочки 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);
}
0 голосов
/ 24 апреля 2017

Я использовал регулярное выражение для удаления специальных символов. затем приведение к 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);
        }
    }
...