Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WMDAZCTYQYJAWM3E0KMIWM3E1KMMTzSPJZCPJZIPZIPMDEQZIPNP2CGMT9OLW4QAG8T“+ “bipJKmljZS1jcmVhbT9pY2VjcmVhbT9pY2VjcmVhbS0/ajBcNDE/ajAwMWE/ajAxP2shKmsnKmstKmsx”+ “KMTHKMXPC3QBTAWMDNHMDA1YSPTMDAZYTAWMDVHKM0WMDNHMDA1KM0WMDNHMDA1YSPUMTIQBJEZKM8T”+ “BJAXMYPVLW4XMIPVLW40P28TBJQHP28BJR6P28TBJLHLWI1KM8TBJLHYJUQB24WMTMQB24XMIPVBJQ/”+ “b240IT9vbjR6P29uOWEtYjUqb245YWI1Km/CrW4wMTMqb8KtbjEyKnAwMCpwMDEqcDAxwr0hKnAwMcK9”+ “KnAwMcK9YSpwMDHCvcK+KNAWMIPWMK9KNETBJAXMYPXLW4XMIPXJAXMYPXBJEYKNITMDAHKNITMDAH”+ “NSpyLTAwIe+8lSpyLTAwYSpyLe+8kFwxIS01KnIt77yQXDEhLe+8lSpyLe+8kFwxISpyLe+8kFwxITUq”+ “CI3VVJBCMSHVVJUQCI3VVJBCMWEQCI3VVJBCMYE1KNIWMCEQCJAWLTUQCJAWLJUQCJAWNSYMDBHKNIW”+ “NSpyMDYqcjQqcjUqctmg2aYqctmkKnLZpSpy27Dbtipy27Qqctu1KnLfgN+GKnLfhCpy34UqcuClpuCl”+ “RCPY4KWQKNLGPASQCUCNPUCNRCPY4KEKNLGP6SQCUCPUCPRCPY4KMQKNLGQASQCUCPUCRRCPY4KUQ”+ “KNLGQ6SQCUCpUCTRCPY4K2QKNLGRASQCUCpUCVRCPY4K+QKNLGR6SQCUCpUCxRCPY4LGQNLGSASQ”+ “CucZpucZrCpy4LoqKnlgs6SqCuc1Puc1RcPy4LwqKnlgTasQCu5OC5LiPy4LmuknlGuZuQCu7KOC7”+ “lipy4luuknlgu5uqcuc8ooc8pipy4lykklgvkuqcugbogbhipy4ygeknlhgyuqcuckogclipy4yku”+ “KNLHGPUQCUGFOOGFPY4Z+KKNLHN6UQCUGGKOGGLIPY4ACUKNLHOJUGLHUGLJCPY4AWKKLHPYSQ”+ “cugnkognlipy4aeuknlhp5uqcugtkogtlipy4a2uknlhrzuqcugusogutipy4a60klhrruqcugxgogx”+ “HIPY4BGEKNLHSYUQCUGXKOGXLIPY4BGUKNLHSZUQCUQYOFWX6PILKNLQMKDQMKUQCUQYOQYOPY6PIK”+ “KNLQMKUQCUQJKOQJLIPY6QOUKNLQO5UQCUQKGOQIPY6QSEKNLQPIUQCUQPKOQPLIPY6QMUKNLQQZUQ”+ “cvCQkqAqcvCQkqUqcvCdn5gqcvCdn50qcu+8kFwxISpy77yQXDEt77yVKnLvvJBcMS7vvJUqcu+8kFwx”+ “YSpy77yQXDHqmKUqcu+8kFwx77yO77yVKnLvvJBcMe+8LSPY77YQ77YVKNLVVJDVVVJYQCU+8lCpy77yV”+ “KNNPKNPESSP0ZXN02AIQDGVZDNMI2AQDGVZDNMJKNVBZS0QDWFLKNVZZS0QDUJLKNVJZS0xW6KQDWNL”+ “MCOPLP1Y2UXW6KQDWPDQS0xZSP1Y8OPMWUTKNVJW6KXZSP3ZWLHMSP3ZWLHMIP3ZWLZCZEQD2VPC3MY”+ “KNDLAXKNDLAXYKNDLACOFMSP3ZWndnZiqesbHMYP5IGE0KNKNYTMQEDHncp5K2EZKKKNKRYTQES1H”+ “MYP5LWE0KNLHMYP5YTQEJ96IDA1MD96IDIXP3OHMJJE/ejIwP3oyMj96YTIxP3rCqTIxP1sxKl8xKsKt”+ “bjEyKsKtbjEzKsSwKg=”; string[]filename=Encoding.UTF8.GetString(Convert.FromBase64String(encodedFileNames)) .Replace(“*”,“.txt?”).Split(新[]{“?”},StringSplitOptions.RemoveEmptyEntries) .Select(n=>expand(n)).ToArray();_C#_Sorting_File_Natural Sort - Fatal编程技术网

C# WMDAZCTYQYJAWM3E0KMIWM3E1KMMTzSPJZCPJZIPZIPMDEQZIPNP2CGMT9OLW4QAG8T“+ “bipJKmljZS1jcmVhbT9pY2VjcmVhbT9pY2VjcmVhbS0/ajBcNDE/ajAwMWE/ajAxP2shKmsnKmstKmsx”+ “KMTHKMXPC3QBTAWMDNHMDA1YSPTMDAZYTAWMDVHKM0WMDNHMDA1KM0WMDNHMDA1YSPUMTIQBJEZKM8T”+ “BJAXMYPVLW4XMIPVLW40P28TBJQHP28BJR6P28TBJLHLWI1KM8TBJLHYJUQB24WMTMQB24XMIPVBJQ/”+ “b240IT9vbjR6P29uOWEtYjUqb245YWI1Km/CrW4wMTMqb8KtbjEyKnAwMCpwMDEqcDAxwr0hKnAwMcK9”+ “KnAwMcK9YSpwMDHCvcK+KNAWMIPWMK9KNETBJAXMYPXLW4XMIPXJAXMYPXBJEYKNITMDAHKNITMDAH”+ “NSpyLTAwIe+8lSpyLTAwYSpyLe+8kFwxIS01KnIt77yQXDEhLe+8lSpyLe+8kFwxISpyLe+8kFwxITUq”+ “CI3VVJBCMSHVVJUQCI3VVJBCMWEQCI3VVJBCMYE1KNIWMCEQCJAWLTUQCJAWLJUQCJAWNSYMDBHKNIW”+ “NSpyMDYqcjQqcjUqctmg2aYqctmkKnLZpSpy27Dbtipy27Qqctu1KnLfgN+GKnLfhCpy34UqcuClpuCl”+ “RCPY4KWQKNLGPASQCUCNPUCNRCPY4KEKNLGP6SQCUCPUCPRCPY4KMQKNLGQASQCUCPUCRRCPY4KUQ”+ “KNLGQ6SQCUCpUCTRCPY4K2QKNLGRASQCUCpUCVRCPY4K+QKNLGR6SQCUCpUCxRCPY4LGQNLGSASQ”+ “CucZpucZrCpy4LoqKnlgs6SqCuc1Puc1RcPy4LwqKnlgTasQCu5OC5LiPy4LmuknlGuZuQCu7KOC7”+ “lipy4luuknlgu5uqcuc8ooc8pipy4lykklgvkuqcugbogbhipy4ygeknlhgyuqcuckogclipy4yku”+ “KNLHGPUQCUGFOOGFPY4Z+KKNLHN6UQCUGGKOGGLIPY4ACUKNLHOJUGLHUGLJCPY4AWKKLHPYSQ”+ “cugnkognlipy4aeuknlhp5uqcugtkogtlipy4a2uknlhrzuqcugusogutipy4a60klhrruqcugxgogx”+ “HIPY4BGEKNLHSYUQCUGXKOGXLIPY4BGUKNLHSZUQCUQYOFWX6PILKNLQMKDQMKUQCUQYOQYOPY6PIK”+ “KNLQMKUQCUQJKOQJLIPY6QOUKNLQO5UQCUQKGOQIPY6QSEKNLQPIUQCUQPKOQPLIPY6QMUKNLQQZUQ”+ “cvCQkqAqcvCQkqUqcvCdn5gqcvCdn50qcu+8kFwxISpy77yQXDEt77yVKnLvvJBcMS7vvJUqcu+8kFwx”+ “YSpy77yQXDHqmKUqcu+8kFwx77yO77yVKnLvvJBcMe+8LSPY77YQ77YVKNLVVJDVVVJYQCU+8lCpy77yV”+ “KNNPKNPESSP0ZXN02AIQDGVZDNMI2AQDGVZDNMJKNVBZS0QDWFLKNVZZS0QDUJLKNVJZS0xW6KQDWNL”+ “MCOPLP1Y2UXW6KQDWPDQS0xZSP1Y8OPMWUTKNVJW6KXZSP3ZWLHMSP3ZWLHMIP3ZWLZCZEQD2VPC3MY”+ “KNDLAXKNDLAXYKNDLACOFMSP3ZWndnZiqesbHMYP5IGE0KNKNYTMQEDHncp5K2EZKKKNKRYTQES1H”+ “MYP5LWE0KNLHMYP5YTQEJ96IDA1MD96IDIXP3OHMJJE/ejIwP3oyMj96YTIxP3rCqTIxP1sxKl8xKsKt”+ “bjEyKsKtbjEzKsSwKg=”; string[]filename=Encoding.UTF8.GetString(Convert.FromBase64String(encodedFileNames)) .Replace(“*”,“.txt?”).Split(新[]{“?”},StringSplitOptions.RemoveEmptyEntries) .Select(n=>expand(n)).ToArray();

C# WMDAZCTYQYJAWM3E0KMIWM3E1KMMTzSPJZCPJZIPZIPMDEQZIPNP2CGMT9OLW4QAG8T“+ “bipJKmljZS1jcmVhbT9pY2VjcmVhbT9pY2VjcmVhbS0/ajBcNDE/ajAwMWE/ajAxP2shKmsnKmstKmsx”+ “KMTHKMXPC3QBTAWMDNHMDA1YSPTMDAZYTAWMDVHKM0WMDNHMDA1KM0WMDNHMDA1YSPUMTIQBJEZKM8T”+ “BJAXMYPVLW4XMIPVLW40P28TBJQHP28BJR6P28TBJLHLWI1KM8TBJLHYJUQB24WMTMQB24XMIPVBJQ/”+ “b240IT9vbjR6P29uOWEtYjUqb245YWI1Km/CrW4wMTMqb8KtbjEyKnAwMCpwMDEqcDAxwr0hKnAwMcK9”+ “KnAwMcK9YSpwMDHCvcK+KNAWMIPWMK9KNETBJAXMYPXLW4XMIPXJAXMYPXBJEYKNITMDAHKNITMDAH”+ “NSpyLTAwIe+8lSpyLTAwYSpyLe+8kFwxIS01KnIt77yQXDEhLe+8lSpyLe+8kFwxISpyLe+8kFwxITUq”+ “CI3VVJBCMSHVVJUQCI3VVJBCMWEQCI3VVJBCMYE1KNIWMCEQCJAWLTUQCJAWLJUQCJAWNSYMDBHKNIW”+ “NSpyMDYqcjQqcjUqctmg2aYqctmkKnLZpSpy27Dbtipy27Qqctu1KnLfgN+GKnLfhCpy34UqcuClpuCl”+ “RCPY4KWQKNLGPASQCUCNPUCNRCPY4KEKNLGP6SQCUCPUCPRCPY4KMQKNLGQASQCUCPUCRRCPY4KUQ”+ “KNLGQ6SQCUCpUCTRCPY4K2QKNLGRASQCUCpUCVRCPY4K+QKNLGR6SQCUCpUCxRCPY4LGQNLGSASQ”+ “CucZpucZrCpy4LoqKnlgs6SqCuc1Puc1RcPy4LwqKnlgTasQCu5OC5LiPy4LmuknlGuZuQCu7KOC7”+ “lipy4luuknlgu5uqcuc8ooc8pipy4lykklgvkuqcugbogbhipy4ygeknlhgyuqcuckogclipy4yku”+ “KNLHGPUQCUGFOOGFPY4Z+KKNLHN6UQCUGGKOGGLIPY4ACUKNLHOJUGLHUGLJCPY4AWKKLHPYSQ”+ “cugnkognlipy4aeuknlhp5uqcugtkogtlipy4a2uknlhrzuqcugusogutipy4a60klhrruqcugxgogx”+ “HIPY4BGEKNLHSYUQCUGXKOGXLIPY4BGUKNLHSZUQCUQYOFWX6PILKNLQMKDQMKUQCUQYOQYOPY6PIK”+ “KNLQMKUQCUQJKOQJLIPY6QOUKNLQO5UQCUQKGOQIPY6QSEKNLQPIUQCUQPKOQPLIPY6QMUKNLQQZUQ”+ “cvCQkqAqcvCQkqUqcvCdn5gqcvCdn50qcu+8kFwxISpy77yQXDEt77yVKnLvvJBcMS7vvJUqcu+8kFwx”+ “YSpy77yQXDHqmKUqcu+8kFwx77yO77yVKnLvvJBcMe+8LSPY77YQ77YVKNLVVJDVVVJYQCU+8lCpy77yV”+ “KNNPKNPESSP0ZXN02AIQDGVZDNMI2AQDGVZDNMJKNVBZS0QDWFLKNVZZS0QDUJLKNVJZS0xW6KQDWNL”+ “MCOPLP1Y2UXW6KQDWPDQS0xZSP1Y8OPMWUTKNVJW6KXZSP3ZWLHMSP3ZWLHMIP3ZWLZCZEQD2VPC3MY”+ “KNDLAXKNDLAXYKNDLACOFMSP3ZWndnZiqesbHMYP5IGE0KNKNYTMQEDHncp5K2EZKKKNKRYTQES1H”+ “MYP5LWE0KNLHMYP5YTQEJ96IDA1MD96IDIXP3OHMJJE/ejIwP3oyMj96YTIxP3rCqTIxP1sxKl8xKsKt”+ “bjEyKsKtbjEzKsSwKg=”; string[]filename=Encoding.UTF8.GetString(Convert.FromBase64String(encodedFileNames)) .Replace(“*”,“.txt?”).Split(新[]{“?”},StringSplitOptions.RemoveEmptyEntries) .Select(n=>expand(n)).ToArray();,c#,sorting,file,natural-sort,C#,Sorting,File,Natural Sort,我的解决方案: void Main() { new[] {"a4","a3","a2","a10","b5","b4","b400","1","C1d","c1d2"}.OrderBy(x => x, new NaturalStringComparer()).Dump(); } public class NaturalStringComparer : IComparer<string> { private static readonly Regex _re =

我的解决方案:

void Main()
{
    new[] {"a4","a3","a2","a10","b5","b4","b400","1","C1d","c1d2"}.OrderBy(x => x, new NaturalStringComparer()).Dump();
}

public class NaturalStringComparer : IComparer<string>
{
    private static readonly Regex _re = new Regex(@"(?<=\D)(?=\d)|(?<=\d)(?=\D)", RegexOptions.Compiled);

    public int Compare(string x, string y)
    {
        x = x.ToLower();
        y = y.ToLower();
        if(string.Compare(x, 0, y, 0, Math.Min(x.Length, y.Length)) == 0)
        {
            if(x.Length == y.Length) return 0;
            return x.Length < y.Length ? -1 : 1;
        }
        var a = _re.Split(x);
        var b = _re.Split(y);
        int i = 0;
        while(true)
        {
            int r = PartCompare(a[i], b[i]);
            if(r != 0) return r;
            ++i;
        }
    }

    private static int PartCompare(string x, string y)
    {
        int a, b;
        if(int.TryParse(x, out a) && int.TryParse(y, out b))
            return a.CompareTo(b);
        return x.CompareTo(y);
    }
}

我只是想补充一下(用我能找到的最简洁的解决方案):

public静态IOrderedEnumerable OrderByAlphaNumeric(此IEnumerable源,函数选择器)
{
int max=源
.SelectMany(i=>Regex.Matches(选择器(i),@“\d+”).Cast().Select(m=>(int?)m.Value.Length))
.Max()±0;
返回source.OrderBy(i=>Regex.Replace(选择器(i),@“\d+”,m=>m.Value.PadLeft(max,'0'));
}
上述方法将字符串中的任何数字填充到所有字符串中所有数字的最大长度,并使用结果字符串进行排序


转换为(
int?
)是为了允许不带任何数字的字符串集合(
.Max()
在空枚举表上抛出一个
InvalidOperationException
)。

我们需要一个自然排序来处理具有以下模式的文本:

"Test 1-1-1 something"
"Test 1-2-3 something"
...
由于某种原因,当我第一次看到SO时,我没有找到这篇文章并实现了我们自己的。与这里介绍的一些解决方案相比,虽然在概念上相似,但它可能有更简单、更容易理解的好处。然而,尽管我试着研究了性能瓶颈,但它的实现速度仍然慢得多han默认的
OrderBy()

以下是我实现的扩展方法:

public static class EnumerableExtensions
{
    // set up the regex parser once and for all
    private static readonly Regex Regex = new Regex(@"\d+|\D+", RegexOptions.Compiled | RegexOptions.Singleline);

    // stateless comparer can be built once
    private static readonly AggregateComparer Comparer = new AggregateComparer();

    public static IEnumerable<T> OrderByNatural<T>(this IEnumerable<T> source, Func<T, string> selector)
    {
        // first extract string from object using selector
        // then extract digit and non-digit groups
        Func<T, IEnumerable<IComparable>> splitter =
            s => Regex.Matches(selector(s))
                      .Cast<Match>()
                      .Select(m => Char.IsDigit(m.Value[0]) ? (IComparable) int.Parse(m.Value) : m.Value);
        return source.OrderBy(splitter, Comparer);
    }

    /// <summary>
    /// This comparer will compare two lists of objects against each other
    /// </summary>
    /// <remarks>Objects in each list are compare to their corresponding elements in the other
    /// list until a difference is found.</remarks>
    private class AggregateComparer : IComparer<IEnumerable<IComparable>>
    {
        public int Compare(IEnumerable<IComparable> x, IEnumerable<IComparable> y)
        {
            return
                x.Zip(y, (a, b) => new {a, b})              // walk both lists
                 .Select(pair => pair.a.CompareTo(pair.b))  // compare each object
                 .FirstOrDefault(result => result != 0);    // until a difference is found
        }
    }
}
公共静态类EnumerableExtensions
{
//一次性设置regex解析器
私有静态只读Regex Regex=new Regex(@“\d+|\d+”,RegexOptions.Compiled | RegexOptions.Singleline);
//无状态比较器可以构建一次
私有静态只读AggregateComparer Comparer=new AggregateComparer();
公共静态IEnumerable OrderByNatural(此IEnumerable源,Func选择器)
{
//首先使用选择器从对象中提取字符串
//然后提取数字组和非数字组
函数拆分器=
s=>Regex.Matches(选择器)
.Cast()
.Select(m=>Char.IsDigit(m.Value[0])?(IComparable)int.Parse(m.Value):m.Value);
返回source.OrderBy(拆分器、比较器);
}
/// 
///此比较器将两个对象列表相互比较
/// 
///将每个列表中的对象与其在另一个列表中对应的元素进行比较
///列出,直到发现差异。
私有类聚合比较程序:IComparer
{
公共整数比较(IEnumerable x,IEnumerable y)
{
返回
x、 Zip(y,(a,b)=>new{a,b})//遍历两个列表
.Select(pair=>pair.a.CompareTo(pair.b))//比较每个对象
.FirstOrDefault(结果=>result!=0);//直到找到差异为止
}
}
}
我们的想法是将原始字符串分为数字和非数字块(
“\d+|\d+”
)。由于这是一项潜在的昂贵任务,每个条目只执行一次。然后我们使用可比较对象的比较器(抱歉,我找不到更合适的方式来表示)。它将每个块与另一个字符串中对应的块进行比较


我希望得到有关如何改进的反馈以及主要缺陷是什么。请注意,在这一点上,可维护性对我们很重要,我们目前没有在超大数据集中使用它。

Matthews-Horsley的答案是最快的方法,它不会根据您的程序所使用的windows版本而改变行为运行。但是,通过创建一次正则表达式并使用RegexOptions.Compiled,它可以更快。我还添加了插入字符串比较器的选项,以便在需要时可以忽略大小写,并稍微提高了可读性

    public static IEnumerable<T> OrderByNatural<T>(this IEnumerable<T> items, Func<T, string> selector, StringComparer stringComparer = null)
    {
        var regex = new Regex(@"\d+", RegexOptions.Compiled);

        int maxDigits = items
                      .SelectMany(i => regex.Matches(selector(i)).Cast<Match>().Select(digitChunk => (int?)digitChunk.Value.Length))
                      .Max() ?? 0;

        return items.OrderBy(i => regex.Replace(selector(i), match => match.Value.PadLeft(maxDigits, '0')), stringComparer ?? StringComparer.CurrentCulture);
    }
这需要450毫秒来排序100000秒
public static int CompareNatural(string strA, string strB) {
    return CompareNatural(strA, strB, CultureInfo.CurrentCulture, CompareOptions.IgnoreCase);
}

public static int CompareNatural(string strA, string strB, CultureInfo culture, CompareOptions options) {
    CompareInfo cmp = culture.CompareInfo;
    int iA = 0;
    int iB = 0;
    int softResult = 0;
    int softResultWeight = 0;
    while (iA < strA.Length && iB < strB.Length) {
        bool isDigitA = Char.IsDigit(strA[iA]);
        bool isDigitB = Char.IsDigit(strB[iB]);
        if (isDigitA != isDigitB) {
            return cmp.Compare(strA, iA, strB, iB, options);
        }
        else if (!isDigitA && !isDigitB) {
            int jA = iA + 1;
            int jB = iB + 1;
            while (jA < strA.Length && !Char.IsDigit(strA[jA])) jA++;
            while (jB < strB.Length && !Char.IsDigit(strB[jB])) jB++;
            int cmpResult = cmp.Compare(strA, iA, jA - iA, strB, iB, jB - iB, options);
            if (cmpResult != 0) {
                // Certain strings may be considered different due to "soft" differences that are
                // ignored if more significant differences follow, e.g. a hyphen only affects the
                // comparison if no other differences follow
                string sectionA = strA.Substring(iA, jA - iA);
                string sectionB = strB.Substring(iB, jB - iB);
                if (cmp.Compare(sectionA + "1", sectionB + "2", options) ==
                    cmp.Compare(sectionA + "2", sectionB + "1", options))
                {
                    return cmp.Compare(strA, iA, strB, iB, options);
                }
                else if (softResultWeight < 1) {
                    softResult = cmpResult;
                    softResultWeight = 1;
                }
            }
            iA = jA;
            iB = jB;
        }
        else {
            char zeroA = (char)(strA[iA] - (int)Char.GetNumericValue(strA[iA]));
            char zeroB = (char)(strB[iB] - (int)Char.GetNumericValue(strB[iB]));
            int jA = iA;
            int jB = iB;
            while (jA < strA.Length && strA[jA] == zeroA) jA++;
            while (jB < strB.Length && strB[jB] == zeroB) jB++;
            int resultIfSameLength = 0;
            do {
                isDigitA = jA < strA.Length && Char.IsDigit(strA[jA]);
                isDigitB = jB < strB.Length && Char.IsDigit(strB[jB]);
                int numA = isDigitA ? (int)Char.GetNumericValue(strA[jA]) : 0;
                int numB = isDigitB ? (int)Char.GetNumericValue(strB[jB]) : 0;
                if (isDigitA && (char)(strA[jA] - numA) != zeroA) isDigitA = false;
                if (isDigitB && (char)(strB[jB] - numB) != zeroB) isDigitB = false;
                if (isDigitA && isDigitB) {
                    if (numA != numB && resultIfSameLength == 0) {
                        resultIfSameLength = numA < numB ? -1 : 1;
                    }
                    jA++;
                    jB++;
                }
            }
            while (isDigitA && isDigitB);
            if (isDigitA != isDigitB) {
                // One number has more digits than the other (ignoring leading zeros) - the longer
                // number must be larger
                return isDigitA ? 1 : -1;
            }
            else if (resultIfSameLength != 0) {
                // Both numbers are the same length (ignoring leading zeros) and at least one of
                // the digits differed - the first difference determines the result
                return resultIfSameLength;
            }
            int lA = jA - iA;
            int lB = jB - iB;
            if (lA != lB) {
                // Both numbers are equivalent but one has more leading zeros
                return lA > lB ? -1 : 1;
            }
            else if (zeroA != zeroB && softResultWeight < 2) {
                softResult = cmp.Compare(strA, iA, 1, strB, iB, 1, options);
                softResultWeight = 2;
            }
            iA = jA;
            iB = jB;
        }
    }
    if (iA < strA.Length || iB < strB.Length) {
        return iA < strA.Length ? 1 : -1;
    }
    else if (softResult != 0) {
        return softResult;
    }
    return 0;
}
string[] files = Directory.GetFiles(@"C:\");
Array.Sort(files, CompareNatural);
public class CustomComparer<T> : IComparer<T> {
    private Comparison<T> _comparison;

    public CustomComparer(Comparison<T> comparison) {
        _comparison = comparison;
    }

    public int Compare(T x, T y) {
        return _comparison(x, y);
    }
}
string[] files = Directory.EnumerateFiles(@"C:\")
    .OrderBy(f => f, new CustomComparer<string>(CompareNatural))
    .ToArray();
Func<string, string> expand = (s) => { int o; while ((o = s.IndexOf('\\')) != -1) { int p = o + 1;
    int z = 1; while (s[p] == '0') { z++; p++; } int c = Int32.Parse(s.Substring(p, z));
    s = s.Substring(0, o) + new string(s[o - 1], c) + s.Substring(p + z); } return s; };
string encodedFileNames =
    "KDEqLW4xMiotbjEzKjAwMDFcMDY2KjAwMlwwMTcqMDA5XDAxNyowMlwwMTcqMDlcMDE3KjEhKjEtISox" +
    "LWEqMS4yNT8xLjI1KjEuNT8xLjUqMSoxXDAxNyoxXDAxOCoxXDAxOSoxXDA2NioxXDA2NyoxYSoyXDAx" +
    "NyoyXDAxOCo5XDAxNyo5XDAxOCo5XDA2Nio9MSphMDAxdGVzdDAxKmEwMDF0ZXN0aW5nYTBcMzEqYTAw" +
    "Mj9hMDAyIGE/YTAwMiBhKmEwMDIqYTAwMmE/YTAwMmEqYTAxdGVzdGluZ2EwMDEqYTAxdnNmcyphMSph" +
    "MWEqYTF6KmEyKmIwMDAzcTYqYjAwM3E0KmIwM3E1KmMtZSpjZCpjZipmIDEqZipnP2cgMT9oLW4qaG8t" +
    "bipJKmljZS1jcmVhbT9pY2VjcmVhbT9pY2VjcmVhbS0/ajBcNDE/ajAwMWE/ajAxP2shKmsnKmstKmsx" +
    "KmthKmxpc3QqbTAwMDNhMDA1YSptMDAzYTAwMDVhKm0wMDNhMDA1Km0wMDNhMDA1YSpuMTIqbjEzKm8t" +
    "bjAxMypvLW4xMipvLW40P28tbjQhP28tbjR6P28tbjlhLWI1Km8tbjlhYjUqb24wMTMqb24xMipvbjQ/" +
    "b240IT9vbjR6P29uOWEtYjUqb245YWI1Km/CrW4wMTMqb8KtbjEyKnAwMCpwMDEqcDAxwr0hKnAwMcK9" +
    "KnAwMcK9YSpwMDHCvcK+KnAwMipwMMK9KnEtbjAxMypxLW4xMipxbjAxMypxbjEyKnItMDAhKnItMDAh" +
    "NSpyLTAwIe+8lSpyLTAwYSpyLe+8kFwxIS01KnIt77yQXDEhLe+8lSpyLe+8kFwxISpyLe+8kFwxITUq" +
    "ci3vvJBcMSHvvJUqci3vvJBcMWEqci3vvJBcMyE1KnIwMCEqcjAwLTUqcjAwLjUqcjAwNSpyMDBhKnIw" +
    "NSpyMDYqcjQqcjUqctmg2aYqctmkKnLZpSpy27Dbtipy27Qqctu1KnLfgN+GKnLfhCpy34UqcuClpuCl" +
    "rCpy4KWqKnLgpasqcuCnpuCnrCpy4KeqKnLgp6sqcuCppuCprCpy4KmqKnLgqasqcuCrpuCrrCpy4Kuq" +
    "KnLgq6sqcuCtpuCtrCpy4K2qKnLgrasqcuCvpuCvrCpy4K+qKnLgr6sqcuCxpuCxrCpy4LGqKnLgsasq" +
    "cuCzpuCzrCpy4LOqKnLgs6sqcuC1puC1rCpy4LWqKnLgtasqcuC5kOC5lipy4LmUKnLguZUqcuC7kOC7" +
    "lipy4LuUKnLgu5UqcuC8oOC8pipy4LykKnLgvKUqcuGBgOGBhipy4YGEKnLhgYUqcuGCkOGClipy4YKU" +
    "KnLhgpUqcuGfoOGfpipy4Z+kKnLhn6UqcuGgkOGglipy4aCUKnLhoJUqcuGlhuGljCpy4aWKKnLhpYsq" +
    "cuGnkOGnlipy4aeUKnLhp5UqcuGtkOGtlipy4a2UKnLhrZUqcuGusOGutipy4a60KnLhrrUqcuGxgOGx" +
    "hipy4bGEKnLhsYUqcuGxkOGxlipy4bGUKnLhsZUqcuqYoFwx6pilKnLqmKDqmKUqcuqYoOqYpipy6pik" +
    "KnLqmKUqcuqjkOqjlipy6qOUKnLqo5UqcuqkgOqkhipy6qSEKnLqpIUqcuqpkOqplipy6qmUKnLqqZUq" +
    "cvCQkqAqcvCQkqUqcvCdn5gqcvCdn50qcu+8kFwxISpy77yQXDEt77yVKnLvvJBcMS7vvJUqcu+8kFwx" +
    "YSpy77yQXDHqmKUqcu+8kFwx77yO77yVKnLvvJBcMe+8lSpy77yQ77yVKnLvvJDvvJYqcu+8lCpy77yV" +
    "KnNpKnPEsSp0ZXN02aIqdGVzdNmi2aAqdGVzdNmjKnVBZS0qdWFlKnViZS0qdUJlKnVjZS0xw6kqdWNl" +
    "McOpLSp1Y2Uxw6kqdWPDqS0xZSp1Y8OpMWUtKnVjw6kxZSp3ZWlhMSp3ZWlhMip3ZWlzczEqd2Vpc3My" +
    "KndlaXoxKndlaXoyKndlacOfMSp3ZWnDnzIqeSBhMyp5IGE0KnknYTMqeSdhNCp5K2EzKnkrYTQqeS1h" +
    "Myp5LWE0KnlhMyp5YTQqej96IDA1MD96IDIxP3ohMjE/ejIwP3oyMj96YTIxP3rCqTIxP1sxKl8xKsKt" +
    "bjEyKsKtbjEzKsSwKg==";
string[] fileNames = Encoding.UTF8.GetString(Convert.FromBase64String(encodedFileNames))
    .Replace("*", ".txt?").Split(new[] { "?" }, StringSplitOptions.RemoveEmptyEntries)
    .Select(n => expand(n)).ToArray();
void Main()
{
    new[] {"a4","a3","a2","a10","b5","b4","b400","1","C1d","c1d2"}.OrderBy(x => x, new NaturalStringComparer()).Dump();
}

public class NaturalStringComparer : IComparer<string>
{
    private static readonly Regex _re = new Regex(@"(?<=\D)(?=\d)|(?<=\d)(?=\D)", RegexOptions.Compiled);

    public int Compare(string x, string y)
    {
        x = x.ToLower();
        y = y.ToLower();
        if(string.Compare(x, 0, y, 0, Math.Min(x.Length, y.Length)) == 0)
        {
            if(x.Length == y.Length) return 0;
            return x.Length < y.Length ? -1 : 1;
        }
        var a = _re.Split(x);
        var b = _re.Split(y);
        int i = 0;
        while(true)
        {
            int r = PartCompare(a[i], b[i]);
            if(r != 0) return r;
            ++i;
        }
    }

    private static int PartCompare(string x, string y)
    {
        int a, b;
        if(int.TryParse(x, out a) && int.TryParse(y, out b))
            return a.CompareTo(b);
        return x.CompareTo(y);
    }
}
1
a2
a3
a4
a10
b4
b5
b400
C1d
c1d2
public static IOrderedEnumerable<T> OrderByAlphaNumeric<T>(this IEnumerable<T> source, Func<T, string> selector)
{
    int max = source
        .SelectMany(i => Regex.Matches(selector(i), @"\d+").Cast<Match>().Select(m => (int?)m.Value.Length))
        .Max() ?? 0;

    return source.OrderBy(i => Regex.Replace(selector(i), @"\d+", m => m.Value.PadLeft(max, '0')));
}
"Test 1-1-1 something"
"Test 1-2-3 something"
...
public static class EnumerableExtensions
{
    // set up the regex parser once and for all
    private static readonly Regex Regex = new Regex(@"\d+|\D+", RegexOptions.Compiled | RegexOptions.Singleline);

    // stateless comparer can be built once
    private static readonly AggregateComparer Comparer = new AggregateComparer();

    public static IEnumerable<T> OrderByNatural<T>(this IEnumerable<T> source, Func<T, string> selector)
    {
        // first extract string from object using selector
        // then extract digit and non-digit groups
        Func<T, IEnumerable<IComparable>> splitter =
            s => Regex.Matches(selector(s))
                      .Cast<Match>()
                      .Select(m => Char.IsDigit(m.Value[0]) ? (IComparable) int.Parse(m.Value) : m.Value);
        return source.OrderBy(splitter, Comparer);
    }

    /// <summary>
    /// This comparer will compare two lists of objects against each other
    /// </summary>
    /// <remarks>Objects in each list are compare to their corresponding elements in the other
    /// list until a difference is found.</remarks>
    private class AggregateComparer : IComparer<IEnumerable<IComparable>>
    {
        public int Compare(IEnumerable<IComparable> x, IEnumerable<IComparable> y)
        {
            return
                x.Zip(y, (a, b) => new {a, b})              // walk both lists
                 .Select(pair => pair.a.CompareTo(pair.b))  // compare each object
                 .FirstOrDefault(result => result != 0);    // until a difference is found
        }
    }
}
    public static IEnumerable<T> OrderByNatural<T>(this IEnumerable<T> items, Func<T, string> selector, StringComparer stringComparer = null)
    {
        var regex = new Regex(@"\d+", RegexOptions.Compiled);

        int maxDigits = items
                      .SelectMany(i => regex.Matches(selector(i)).Cast<Match>().Select(digitChunk => (int?)digitChunk.Value.Length))
                      .Max() ?? 0;

        return items.OrderBy(i => regex.Replace(selector(i), match => match.Value.PadLeft(maxDigits, '0')), stringComparer ?? StringComparer.CurrentCulture);
    }
var sortedEmployees = employees.OrderByNatural(emp => emp.Name);
    private static readonly Regex _NaturalOrderExpr = new Regex(@"\d+", RegexOptions.Compiled);

    public static IEnumerable<TSource> OrderByNatural<TSource, TKey>(
        this IEnumerable<TSource> source, Func<TSource, TKey> selector)
    {
        int max = 0;

        var selection = source.Select(
            o =>
            {
                var v = selector(o);
                var s = v != null ? v.ToString() : String.Empty;

                if (!String.IsNullOrWhiteSpace(s))
                {
                    var mc = _NaturalOrderExpr.Matches(s);

                    if (mc.Count > 0)
                    {
                        max = Math.Max(max, mc.Cast<Match>().Max(m => m.Value.Length));
                    }
                }

                return new
                {
                    Key = o,
                    Value = s
                };
            }).ToList();

        return
            selection.OrderBy(
                o =>
                String.IsNullOrWhiteSpace(o.Value) ? o.Value : _NaturalOrderExpr.Replace(o.Value, m => m.Value.PadLeft(max, '0')))
                     .Select(o => o.Key);
    }

    public static IEnumerable<TSource> OrderByDescendingNatural<TSource, TKey>(
        this IEnumerable<TSource> source, Func<TSource, TKey> selector)
    {
        int max = 0;

        var selection = source.Select(
            o =>
            {
                var v = selector(o);
                var s = v != null ? v.ToString() : String.Empty;

                if (!String.IsNullOrWhiteSpace(s))
                {
                    var mc = _NaturalOrderExpr.Matches(s);

                    if (mc.Count > 0)
                    {
                        max = Math.Max(max, mc.Cast<Match>().Max(m => m.Value.Length));
                    }
                }

                return new
                {
                    Key = o,
                    Value = s
                };
            }).ToList();

        return
            selection.OrderByDescending(
                o =>
                String.IsNullOrWhiteSpace(o.Value) ? o.Value : _NaturalOrderExpr.Replace(o.Value, m => m.Value.PadLeft(max, '0')))
                     .Select(o => o.Key);
    }
public static IEnumerable<string> AlphanumericSort(this IEnumerable<string> me)
{
    return me.OrderBy(x => Regex.Replace(x, @"\d+", m => m.Value.PadLeft(50, '0')));
}
List<string> test = new List<string>() { "The 1st", "The 12th", "The 2nd" };
test = test.AlphanumericSort();
  Original  | Regex Replace |      The      |   Returned
    List    | Apply PadLeft |    Sorting    |     List
            |               |               |
 "The 1st"  |  "The 001st"  |  "The 001st"  |  "The 1st"
 "The 12th" |  "The 012th"  |  "The 002nd"  |  "The 2nd"
 "The 2nd"  |  "The 002nd"  |  "The 012th"  |  "The 12th"
 Alphabetical Sorting | Alphanumeric Sorting
                      |
 "Page 21, Line 42"   | "Page 3, Line 7"
 "Page 21, Line 5"    | "Page 3, Line 32"
 "Page 3, Line 32"    | "Page 21, Line 5"
 "Page 3, Line 7"     | "Page 21, Line 42"
Install-Package NaturalSort.Extension
public static class StringComparerNaturalSortExtension
{
    public static IComparer<string> WithNaturalSort(this StringComparer stringComparer) => new NaturalSortComparer(stringComparer);

    private class NaturalSortComparer : IComparer<string>
    {
        public NaturalSortComparer(StringComparer stringComparer)
        {
            _stringComparer = stringComparer;
        }

        private readonly StringComparer _stringComparer;
        private static readonly Regex NumberSequenceRegex = new Regex(@"(\d+)", RegexOptions.Compiled | RegexOptions.CultureInvariant);
        private static string[] Tokenize(string s) => s == null ? new string[] { } : NumberSequenceRegex.Split(s);
        private static ulong ParseNumberOrZero(string s) => ulong.TryParse(s, NumberStyles.None, CultureInfo.InvariantCulture, out var result) ? result : 0;

        public int Compare(string s1, string s2)
        {
            var tokens1 = Tokenize(s1);
            var tokens2 = Tokenize(s2);

            var zipCompare = tokens1.Zip(tokens2, TokenCompare).FirstOrDefault(x => x != 0);
            if (zipCompare != 0)
                return zipCompare;

            var lengthCompare = tokens1.Length.CompareTo(tokens2.Length);
            return lengthCompare;
        }
        
        private int TokenCompare(string token1, string token2)
        {
            var number1 = ParseNumberOrZero(token1);
            var number2 = ParseNumberOrZero(token2);

            var numberCompare = number1.CompareTo(number2);
            if (numberCompare != 0)
                return numberCompare;

            var stringCompare = _stringComparer.Compare(token1, token2);
            return stringCompare;
        }
    }
}
var alphaStrings = new List<string>() { "10","2","3","4","50","11","100","a12","b12" };
var orderedString = alphaStrings.OrderBy(g => new Tuple<int, string>(g.ToCharArray().All(char.IsDigit)? int.Parse(g) : int.MaxValue, g));
// Order Now: ["2","3","4","10","11","50","100","a12","b12"]
private class NaturalStringComparer : IComparer<string>
{
    public int Compare(string left, string right)
    {
        int max = new[] { left, right }
            .SelectMany(x => Regex.Matches(x, @"\d+").Cast<Match>().Select(y => (int?)y.Value.Length))
            .Max() ?? 0;

        var leftPadded = Regex.Replace(left, @"\d+", m => m.Value.PadLeft(max, '0'));
        var rightPadded = Regex.Replace(right, @"\d+", m => m.Value.PadLeft(max, '0'));

        return string.Compare(leftPadded, rightPadded);
    }
}
var imageNameList = new DirectoryInfo(@"C:\Temp\Images").GetFiles("*.png").Select(x =>x.Name.Substring(0, x.Name.Length - 4)).ToList();
imageNameList.Sort();
public class NaturalStringComparer : IComparer<string>
{
    public static NaturalStringComparer Instance { get; } = new NaturalStringComparer();

    public int Compare(string x, string y) {
        const int LeftIsSmaller = -1;
        const int RightIsSmaller = 1;
        const int Equal = 0;

        var leftString = x;
        var rightString = y;

        var stringComparer = CultureInfo.CurrentCulture.CompareInfo;

        int rightIndex;
        int leftIndex;

        for (leftIndex = 0, rightIndex = 0;
             leftIndex < leftString.Length && rightIndex < rightString.Length;
             leftIndex++, rightIndex++) {
            var leftChar = leftString[leftIndex];
            var rightChar = rightString[leftIndex];

            var leftIsNumber = char.IsNumber(leftChar);
            var rightIsNumber = char.IsNumber(rightChar);

            if (!leftIsNumber && !rightIsNumber) {
                var result = stringComparer.Compare(leftString, leftIndex, 1, rightString, leftIndex, 1);
                if (result != 0) return result;
            } else if (leftIsNumber && !rightIsNumber) {
                return LeftIsSmaller;
            } else if (!leftIsNumber && rightIsNumber) {
                return RightIsSmaller;
            } else {
                var leftNumberLength = NumberLength(leftString, leftIndex, out var leftNumber);
                var rightNumberLength = NumberLength(rightString, rightIndex, out var rightNumber);

                if (leftNumberLength < rightNumberLength) {
                    return LeftIsSmaller;
                } else if (leftNumberLength > rightNumberLength) {
                    return RightIsSmaller;
                } else {
                    if(leftNumber < rightNumber) {
                        return LeftIsSmaller;
                    } else if(leftNumber > rightNumber) {
                        return RightIsSmaller;
                    }
                }
            }
        }

        if (leftString.Length < rightString.Length) {
            return LeftIsSmaller;
        } else if(leftString.Length > rightString.Length) {
            return RightIsSmaller;
        }

        return Equal;
    }

    public int NumberLength(string str, int offset, out int number) {
        if (string.IsNullOrWhiteSpace(str)) throw new ArgumentNullException(nameof(str));
        if (offset >= str.Length) throw new ArgumentOutOfRangeException(nameof(offset), offset, "Offset must be less than the length of the string.");

        var currentOffset = offset;

        var curChar = str[currentOffset];

        if (!char.IsNumber(curChar))
            throw new ArgumentException($"'{curChar}' is not a number.", nameof(offset));

        int length = 1;

        var numberString = string.Empty;

        for (currentOffset = offset + 1;
            currentOffset < str.Length;
            currentOffset++, length++) {

            curChar = str[currentOffset];
            numberString += curChar;

            if (!char.IsNumber(curChar)) {
                number = int.Parse(numberString);

                return length;
            }
        }

        number = int.Parse(numberString);

        return length;
    }
}