C#中的自然sorting顺序

任何人都有一个很好的资源,或提供一个在C#中的FileInfo数组自然顺序的样本? 我按照我的种类实现了IComparer接口。

最简单的方法就是在Windows中调用内置函数,并将其用作IComparer的比较函数:

 [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] private static extern int StrCmpLogicalW(string psz1, string psz2); 

迈克尔·卡普兰(Michael Kaplan) 举了一些关于这个function如何工作的例子 ,以及为使Vista更直观地工作而做出的改变。 这个函数的好处在于,它的行为与它所运行的Windows的版本相同,但是这意味着它在Windows版本之间是不同的,所以你需要考虑这是否是一个问题。

所以一个完整的实现将是这样的:

 [SuppressUnmanagedCodeSecurity] internal static class SafeNativeMethods { [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)] public static extern int StrCmpLogicalW(string psz1, string psz2); } public sealed class NaturalStringComparer : IComparer<string> { public int Compare(string a, string b) { return SafeNativeMethods.StrCmpLogicalW(a, b); } } public sealed class NaturalFileInfoNameComparer : IComparer<FileInfo> { public int Compare(FileInfo a, FileInfo b) { return SafeNativeMethods.StrCmpLogicalW(a.Name, b.Name); } } 

只是想我会补充(与最简洁的解决scheme,我可以find):

  public static IEnumerable<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'))); } 

上面填充string中的所有数字的最大长度,并使用结果string进行sorting。

转换为( int? )是为了允许没有任何数字的string集合.Max()在一个空的枚举上的.Max()抛出一个InvalidOperationException )。

没有一个现有的实现看起来很棒,所以我写了自己的。 结果几乎与现代版本的Windows资源pipe理器(Windows 7/8)使用的sorting相同。 我看到的唯一区别是1)虽然Windows曾经(例如XP)处理任何长度的数字,但现在限制为19位数 – 我的是无限的,2)Windows给出了与某些Unicode数字集不一致的结果 – 我的作品很好(虽然它不能在数字上比较代理对的数字; Windows也不能); 3)如果不同部分出现,我不能区分不同types的非主要sorting权重(例如“e-1é”与“ é1e-“ – 前后的部分有变音符号和标点符号的重量差异)。

 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, eg 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; } 

签名与Comparison<string>委托相匹配:

 string[] files = Directory.GetFiles(@"C:\"); Array.Sort(files, CompareNatural); 

这是一个用作IComparer<string>的包装类:

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

这里有一组用于testing的文件名:

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

Pure C#for linq orderby:

http://zootfroot.blogspot.com/2009/09/natural-sort-compare-with-linq-orderby.html

 public class NaturalSortComparer<T> : IComparer<string>, IDisposable { private bool isAscending; public NaturalSortComparer(bool inAscendingOrder = true) { this.isAscending = inAscendingOrder; } #region IComparer<string> Members public int Compare(string x, string y) { throw new NotImplementedException(); } #endregion #region IComparer<string> Members int IComparer<string>.Compare(string x, string y) { if (x == y) return 0; string[] x1, y1; if (!table.TryGetValue(x, out x1)) { x1 = Regex.Split(x.Replace(" ", ""), "([0-9]+)"); table.Add(x, x1); } if (!table.TryGetValue(y, out y1)) { y1 = Regex.Split(y.Replace(" ", ""), "([0-9]+)"); table.Add(y, y1); } int returnVal; for (int i = 0; i < x1.Length && i < y1.Length; i++) { if (x1[i] != y1[i]) { returnVal = PartCompare(x1[i], y1[i]); return isAscending ? returnVal : -returnVal; } } if (y1.Length > x1.Length) { returnVal = 1; } else if (x1.Length > y1.Length) { returnVal = -1; } else { returnVal = 0; } return isAscending ? returnVal : -returnVal; } private static int PartCompare(string left, string right) { int x, y; if (!int.TryParse(left, out x)) return left.CompareTo(right); if (!int.TryParse(right, out y)) return left.CompareTo(right); return x.CompareTo(y); } #endregion private Dictionary<string, string[]> table = new Dictionary<string, string[]>(); public void Dispose() { table.Clear(); table = null; } } 

我的解决scheme

 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 

Matthews Horsleys答案是最快的方法,不会根据您的程序运行在哪个版本的Windows上而改变行为。 但是,通过创build一次正则expression式,并使用RegexOptions.Compiled可以更快。 我还添加了插入string比较器的选项,以便在需要时可以忽略大小写,并提高了可读性。

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

对于默认的.netstring比较,这需要450ms对100000个string进行sorting,相比之下,这是300ms。

你需要小心 – 我隐约记得,读到StrCmpLogicalW或类似的东西不是严格的传递性的,我观察到.NET的sorting方法有时会陷入无限循环,如果比较函数违反规则。

如果a <b和b <c,传递比较总是会报告<c。 有一个函数做自然sorting比较并不总是符合这个标准,但我不记得是否是StrCmpLogicalW或其他。

添加到Greg Beech的答案 (因为我刚刚search),如果你想从Linq使用这个,你可以使用带有IComparerOrderBy 。 例如:

 var items = new List<MyItem>(); // fill items var sorted = items.OrderBy(item => item.Name, new NaturalStringComparer()); 

这是我的代码sorting一个string具有字母和数字字符。

首先,这个扩展方法:

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

它是如何工作的? 通过replace为零:

  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" 

希望这会有所帮助。

扩展了以前的几个答案,并使用扩展方法,我想出了以下内容,没有可能的多枚举枚举的警告,或性能问题与使用多个正则expression式对象,或不必要地调用正则expression式被说,它确实使用ToList(),这可以否定较大集合中的好处。

select器支持通用键入,以允许分配任何委托,源集合中的元素由select器进行变异,然后使用ToString()转换为string。

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

这是一个相对简单的例子,它不使用P / Invoke,并避免执行过程中的任何分配。

 internal sealed class NumericStringComparer : IComparer<string> { public static NumericStringComparer Instance { get; } = new NumericStringComparer(); public int Compare(string x, string y) { // sort nulls to the start if (x == null) return y == null ? 0 : -1; if (y == null) return 1; var ix = 0; var iy = 0; while (true) { // sort shorter strings to the start if (ix >= x.Length) return iy >= y.Length ? 0 : -1; if (iy >= y.Length) return 1; var cx = x[ix]; var cy = y[iy]; int result; if (char.IsDigit(cx) && char.IsDigit(cy)) result = CompareInteger(x, y, ref ix, ref iy); else result = cx.CompareTo(y[iy]); if (result != 0) return result; ix++; iy++; } } private static int CompareInteger(string x, string y, ref int ix, ref int iy) { var lx = GetNumLength(x, ix); var ly = GetNumLength(y, iy); // shorter number first (note, doesn't handle leading zeroes) if (lx != ly) return lx.CompareTo(ly); for (var i = 0; i < lx; i++) { var result = x[ix++].CompareTo(y[iy++]); if (result != 0) return result; } return 0; } private static int GetNumLength(string s, int i) { var length = 0; while (i < s.Length && char.IsDigit(s[i++])) length++; return length; } } 

它不会忽略前导零,所以012之后。

相应的unit testing:

 public class NumericStringComparerTests { [Fact] public void OrdersCorrectly() { AssertEqual("", ""); AssertEqual(null, null); AssertEqual("Hello", "Hello"); AssertEqual("Hello123", "Hello123"); AssertEqual("123", "123"); AssertEqual("123Hello", "123Hello"); AssertOrdered("", "Hello"); AssertOrdered(null, "Hello"); AssertOrdered("Hello", "Hello1"); AssertOrdered("Hello123", "Hello124"); AssertOrdered("Hello123", "Hello133"); AssertOrdered("Hello123", "Hello223"); AssertOrdered("123", "124"); AssertOrdered("123", "133"); AssertOrdered("123", "223"); AssertOrdered("123", "1234"); AssertOrdered("123", "2345"); AssertOrdered("0", "1"); AssertOrdered("123Hello", "124Hello"); AssertOrdered("123Hello", "133Hello"); AssertOrdered("123Hello", "223Hello"); AssertOrdered("123Hello", "1234Hello"); } private static void AssertEqual(string x, string y) { Assert.Equal(0, NumericStringComparer.Instance.Compare(x, y)); Assert.Equal(0, NumericStringComparer.Instance.Compare(y, x)); } private static void AssertOrdered(string x, string y) { Assert.Equal(-1, NumericStringComparer.Instance.Compare(x, y)); Assert.Equal( 1, NumericStringComparer.Instance.Compare(y, x)); } } 

我们需要一种自然的方式来处理以下模式的文本:

 "Test 1-1-1 something" "Test 1-2-3 something" ... 

出于某种原因,当我第一次看到这个,我没有find这个职位,并实施我们自己的。 与这里介绍的一些解决scheme相比,虽然在概念上相似,但它可能具有更简单和更容易理解的好处。 然而,虽然我试图看看性能瓶颈,但它仍然是一个比默认的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 } } } 

我们的想法是将原始string拆分为数字和非数字( "\d+|\D+" )块。 由于这是一个潜在的昂贵的任务,每个条目只能完成一次。 然后,我们使用一个比较对象的比较器(对不起,我找不到一个更正确的方式来说)。 它将每个块与另一个string中相应的块进行比较。

我想就如何改进这个问题提出反馈意见,以及主要的缺陷是什么。 请注意,可维护性对于我们来说至关重要,目前我们还没有在极其庞大的数据集中使用它。

如果你的最终代码是networking(ASP.NET等),然后自然sorting可以通过使用localCampare JavaScript函数来实现

 '10'.localeCompare('2', undefined, {numeric: true, sensitivity: 'base'}) 

https://stackoverflow.com/a/38641281/952018