C # Classificar arquivos por ordem de número natural no nome?

Eu tenho arquivos no diretório como esse

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

….

quando eu carregar arquivos:

 FileInfo[] files = di.GetFiles(); 

Eles entram na ordem errada (eles devem ir como acima):

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

Como consertar isso?

Eu estava tentando classificá-los, mas de jeito nenhum:

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

Alfabeticamente, a ordem “errada” está correta. Se você quiser ordenar numericamente, então você precisará:

  1. converter os nomes de arquivos em uma lista de números numéricos e classificá-los
  2. nomeie os arquivos de modo que a sorting alfabética e numérica seja a mesma (0-001.jpeg e 0-030.jpg)
  3. confie no tempo de criação do arquivo para classificar (presumindo que os arquivos foram criados em ordem).

Veja a resposta para Classificando Directory.GetFiles () para um exemplo de # 3.

Veja a function “CustomSort” aqui .

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

Sua saída:

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

Para resolver esse problema, você pode usar a API do Windows StrCmpLogicalW .

Para mais detalhes veja este artigo .

Eu sei que isso pode ser tarde, mas aqui está outra solução que funciona perfeitamente

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

Usando o Regex, substitua a OrderBy Clause :

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

Então, o que isso faz, ele preenche os valores numéricos no nome do arquivo com um comprimento de 4 caracteres em cada número:

 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 

Mas isso só acontece na cláusula OrderBy , ele não toca no nome do arquivo original de forma alguma. A ordem na qual você terminará na matriz é a ordem “natural humana”.

Seus nomes de arquivos parecem estar estruturados. Se você apenas ordená-los, eles classificam como seqüências de caracteres comuns. Você precisa:

  1. Analise o nome do arquivo em suas partes componentes constituintes.
  2. Converta os segmentos numéricos em um valor numérico.
  3. Compare essa estrutura na ordem desejada para obter a seqüência de intercalação desejada.

Pessoalmente, eu criaria uma class que representasse a estrutura implícita no nome do arquivo. Talvez devesse envolver o FileInfo . O construtor para essa class deve analisar o nome do arquivo em suas partes constituintes e instanciar as propriedades da class apropriadamente.

A class deve implementar IComparable / IComparable (ou você pode criar uma implementação do Comparer ).

Ordene seus objects e eles devem sair na seqüência de ordenação desejada.

Se parece que seus nomes de arquivos são compostos de 3 partes:

  • um valor numérico de alta ordem (vamos chamá-lo de ‘oi’),
  • um valor numérico de baixa ordem (vamos chamá-lo ‘lo’),
  • e uma extensão (vamos chamá-lo ‘ext’)

Então sua class pode parecer algo

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