实现类Windows资源管理器的C#字母数字自然排序
实现类Windows资源管理器的自然排序
要实现和Windows资源管理器一致的自然排序(无需依赖shlwapi.dll),可以通过拆分字符串为字母/数字段,再按照Windows的比较规则逐段比较来完成。以下是完整实现:
核心实现逻辑
Windows自然排序的核心规则:
- 将字符串拆分为连续的数字段和非数字段(包括字母、空格等);
- 数字段先按数值大小比较,数值相同时按段长度排序(前导零多的在前,如
01排在1前面); - 非数字段按不区分大小写的字典序比较,若大小写不同但字典序一致,再按区分大小写排序;
- 数字段整体优先级高于非数字段(纯数字字符串排在字母开头的字符串前)。
代码实现
1. 自然排序比较器
using System; using System.Collections.Generic; using System.Text.RegularExpressions; public class WindowsNaturalComparer : IComparer<string> { private static readonly Regex SegmentRegex = new Regex(@"(\d+|\D+)", RegexOptions.Compiled); public int Compare(string x, string y) { if (x == null && y == null) return 0; if (x == null) return -1; if (y == null) return 1; var xSegments = SegmentRegex.Matches(x); var ySegments = SegmentRegex.Matches(y); int minSegments = Math.Min(xSegments.Count, ySegments.Count); for (int i = 0; i < minSegments; i++) { string xSeg = xSegments[i].Value; string ySeg = ySegments[i].Value; int compareResult; // 判断是否为数字段 if (long.TryParse(xSeg, out long xNum) && long.TryParse(ySeg, out long yNum)) { // 先比较数值 compareResult = xNum.CompareTo(yNum); if (compareResult != 0) return compareResult; // 数值相同则比较段长度(前导零多的在前) compareResult = ySeg.Length.CompareTo(xSeg.Length); if (compareResult != 0) return compareResult; } else { // 非数字段:先不区分大小写比较 compareResult = string.Compare(xSeg, ySeg, StringComparison.OrdinalIgnoreCase); if (compareResult != 0) return compareResult; // 大小写不同但字典序一致时,按区分大小写排序 compareResult = string.Compare(xSeg, ySeg, StringComparison.Ordinal); if (compareResult != 0) return compareResult; } } // 前面的段都匹配,短的字符串排在前面 return xSegments.Count.CompareTo(ySegments.Count); } }
2. 使用示例(验证你的测试数组)
using System; using System.Linq; class Program { static void Main() { var array = new[]{"B01 002", "B01 0010", "01", "B01 001", "B10 001", "B01 01", "1", "B1 001", "B02 001", "A1"}; // 使用自定义比较器排序 var sortedArray = array.OrderBy(s => s, new WindowsNaturalComparer()).ToArray(); Console.WriteLine("排序结果:"); Console.WriteLine(string.Join(", ", sortedArray)); // 输出:01, 1, A1, B01 001, B01 01, B01 002, B01 0010, B1 001, B02 001, B10 001 } }
关键细节说明
- 正则拆分:用
(\d+|\D+)匹配连续数字或非数字,确保字符串被正确拆分为交替的段; - 数字段处理:用
long.TryParse避免整数溢出,数值相同时比较段长度,保证01排在1前面; - 非数字段处理:先不区分大小写比较,符合Windows资源管理器的默认排序行为,再补充区分大小写的比较处理边缘情况;
- 空值处理:兼容
null字符串的比较场景。
内容的提问来源于stack exchange,提问作者theLearner
相关产品推荐
相关产品推荐

