C#按名称中的自然数排序对文件进行排序?

我有像这样的目录中的文件

0-0.jpeg 0-1.jpeg 0-5.jpeg 0-9.jpeg 0-10.jpeg 0-12.jpeg 

….

当我加载文件时:

 FileInfo[] files = di.GetFiles(); 

他们的订单错误(他们应该像上面那样):

 0-0.jpeg 0-1.jpeg 0-10.jpeg 0-12.jpeg 0-5.jpeg 0-9.jpeg 

如何解决?

我试图对它们进行排序,但没办法:

 1) Array.Sort(files, (f1, f2) => f1.Name.CompareTo(f2.Name)); 2) Array.Sort(files, (x, y) => StringComparer.OrdinalIgnoreCase.Compare(x.Name, y.Name)); 

按字母顺序,“错误”的顺序实际上是正确的。 如果你想要按数字排序,那么你需要:

  1. 将文件名转换为数字列表并对其进行排序
  2. 以字母和数字排序相同的方式命名文件(0-001.jpeg和0-030.jpg)
  3. 依赖文件创建时间进行排序(假设文件是​​按顺序创建的)。

有关#3的示例,请参阅排序Directory.GetFiles()的答案。

请在此处查看“CustomSort”function。

 List list = new List() { "0-5.jpeg", "0-9.jpeg", "0-0.jpeg", "0-1.jpeg", "0-10.jpeg", "0-12.jpeg"}; list.CustomSort().ToList().ForEach(x => Console.WriteLine(x)); 

它的输出:

 0-0.jpeg 0-1.jpeg 0-5.jpeg 0-9.jpeg 0-10.jpeg 0-12.jpeg 

要解决此问题,您可以使用StrCmpLogicalW Windows API。

有关详细信息,请参阅此Artice 。

我知道这可能会迟到,但这是另一个完美的解决方案

 FileInfo[] files = di.GetFiles().OrderBy(n => Regex.Replace(n.Name, @"\d+", n => n.Value.PadLeft(4, '0'))); 

OrderBy Clause使用Regex替换:

Regex.Replace(n.Name, @"\d+", n => n.Value.PadLeft(4, '0'))

这样做,它pads文件名中的数值,每个数字的长度为4个字符:

 0-0.jpeg -> 0000-0000.jpeg 0-1.jpeg -> 0000-0001.jpeg 0-5.jpeg -> 0000-0005.jpeg 0-9.jpeg -> 0000-0009.jpeg 0-10.jpeg -> 0000-0010.jpeg 0-12.jpeg -> 0000-0012.jpeg 

但这只发生在OrderBy子句中,它不会以任何方式触及原始文件名。 您最终将在数组中的顺序是“人类自然”顺序。

您的文件名似乎是结构化的。 如果您只是对它们进行排序,它们就像普通的字符 你需要:

  1. 将文件名解析为其组成部分。
  2. 将数字段转换为数字值。
  3. 以所需顺序比较该结构以获得预期的归类序列。

就个人而言,我创建了一个表示文件名中隐含的结构的类。 也许它应该包装FileInfo 。 该类的构造函数应将文件名解析为其组成部分,并适当地实例化该类的属性。

该类应该实现IComparable / IComparable (或者您可以创建Comparer的实现)。

对对象进行排序,然后它们应按照您想要的整理顺序出现。

如果您的文件名看起来像由3部分组成:

  • 一个高阶数值(我们称之为’hi’),
  • 一个低阶数值(让我们称之为’lo’),
  • 和一个扩展(让我们称之为’ext’)

所以你的课可能看起来像

 public class MyFileInfoWrapper : IComparable,IComparable { public MyFileInfoWrapper( FileInfo fi ) { // your implementation here throw new NotImplementedException() ; } public int Hi { get ; private set ; } public int Lo { get ; private set ; } public string Extension { get ; private set ; } public FileInfo FileInfo { get ; private set ; } public int CompareTo( MyFileInfoWrapper other ) { int cc ; if ( other == null ) cc = -1 ; else if ( this.Hi < other.Hi ) cc = -1 ; else if ( this.Hi > other.Hi ) cc = +1 ; else if ( this.Lo < other.Lo ) cc = -1 ; else if ( this.Lo > other.Lo ) cc = +1 ; else cc = string.Compare( this.Extension , other.Extension , StringComparison.InvariantCultureIgnoreCase ) ; return cc ; } public int CompareTo( object obj ) { int cc ; if ( obj == null ) cc = -1 ; else if ( obj is MyFileInfoWrapper ) cc = CompareTo( (MyFileInfoWrapper) obj ) ; else throw new ArgumentException("'obj' is not a 'MyFileInfoWrapper' type.", "obj") ; return cc ; } }