¿Cómo ordenar la lista de archivos por nombre de archivo con número?

Tengo un montón de archivos en un directorio que estoy tratando de obtener basado en su tipo. Una vez que los tenga, me gustaría ordenarlos por nombre de archivo (hay un número en ellos y me gustaría ordenarlos de esa manera)

Mis archivos devueltos son:

file-1.txt file-2.txt ... file-10.txt file-11.txt ... file-20.txt 

Pero el orden en el que los obtengo parece algo más cercano a esto:

 file-1.txt file-10.txt file-11.txt ... file-2.txt file-20.txt 

En este momento estoy usando Directory.GetFiles() y estoy intentando usar la propiedad linq OrderBy . Sin embargo, estoy fallando bastante con lo que necesitaría hacer para ordenar mi lista de archivos como la primera lista anterior.

Directory.GetFiles() parece devolver una lista de cadenas, por lo que no puedo obtener la lista de propiedades del archivo como filename o name .

Aquí está mi código actualmente:

 documentPages = Directory.GetFiles(documentPath, "*.txt").OrderBy(Function(p) p).ToList() 

¿Alguien tiene alguna idea?

Supongo que las partes de file y .txt son mutables, y solo aquí como marcadores de posición para nombres de archivos y tipos que pueden variar.

No uso expresiones regulares muy a menudo, por lo que puede que aún necesite algo de trabajo, pero definitivamente es la dirección que debe seguir:

 Dim exp As String = "-([0-9]+)[.][^.]*$" documentPages = Directory.GetFiles(documentPath, "*.txt").OrderBy(Function(p) Integer.Parse(Regex.Matches(p, exp)(0).Groups(1).Value)).ToList() 

Mirando nuevamente, veo que eché de menos que está filtrando por archivos *.txt , lo que puede ayudarnos a reducir la expresión:

 Dim exp As String = "-([0-9]+)[.]txt$" 

Otra posible mejora aportada por la otra respuesta que incluye datos de prueba es permitir espacios en blanco entre el - y los números:

 Dim exp As String = "-[ ]*([0-9]+)[.]txt$" 

Vale la pena señalar que lo anterior fallará si hay archivos de texto que no siguen el patrón. Podemos contabilizar eso si es necesario:

 Dim exp As String = "-[ ]*([0-9]+)[.][^.]*$" Dim docs = Directory.GetFiles(documentPath, "*.txt") documentPages = docs.OrderBy( Function(p) Dim matches As MatchCollection = Regex.Matches(p, exp) If matches.Count = 0 OrElse matches(0).Groups.Count < 2 Then Return 0 Return Integer.Parse(matches(0).Groups(1).Value) End Function).ToList() 

También puede usar Integer.MaxValue como su opción predeterminada, dependiendo de si desea que aparezcan al principio o al final de la lista.

Parece que podría estar buscando un “NaturalSort”, el tipo de pantalla que File Explorer utiliza para ordenar nombres de archivos que contienen números. Para esto necesita un comparador personalizado:

 Imports System.Runtime.InteropServices Partial Class NativeMethods  Private Shared Function StrCmpLogicalW(s1 As String, s2 As String) As Int32 End Function Friend Shared Function NaturalStringCompare(str1 As String, str2 As String) As Int32 Return StrCmpLogicalW(str1, str2) End Function End Class Public Class NaturalStringComparer Implements IComparer(Of String) Public Function Compare(x As String, y As String) As Integer Implements IComparer(Of String).Compare Return NativeMethods.NaturalStringCompare(x, y) End Function End Class 

Úselo para ordenar los resultados que obtiene:

 Dim myComparer As New NaturalStringComparer ' OP post only shows the filename without path, so strip off path: ' (wont affect the result, just the display) Dim files = Directory.EnumerateFiles(path_name_here). Select(Function(s) Path.GetFileName(s)).ToList Console.WriteLine("Before: {0}", String.Join(", ", files)) ' sort the list using the Natural Comparer: files.Sort(myComparer) Console.WriteLine("After: {0}", String.Join(", ", files)) 

Resultados (alineados para ahorrar espacio):

Antes: archivo-1.txt, archivo-10.txt, archivo-11.txt, archivo-19.txt, archivo-2.txt, archivo-20.txt, archivo-3.txt, archivo-9.txt, archivo-99.txt
Después: archivo-1.txt, archivo-2.txt, archivo-3.txt, archivo-9.txt, archivo-10.txt, archivo-11.txt, archivo-19.txt, archivo-20.txt, archivo-99.txt

Una de las ventajas de esto es que no se basa en un patrón o encoding específica. Es más multiuso y manejará más de un conjunto de números en el texto:

Juego de Tronos \ 4 – A Feast For Crows \ 1 – Prologue.mp3
Juego de Tronos \ 4 – Una Fiesta de Cuervos \ 2 – El Profeta.mp3

Juego de tronos \ 4 – Una fiesta para cuervos \ 10 – Brienne II.mp3
Juego de tronos \ 4 – Una fiesta para cuervos \ 11 – Sansa.mp3


Un Natural String Sort es muy útil, es algo que personalmente no me importa contaminar Intellisense al crear una extensión:

 ' List version  Function ToNaturalSort(l As List(Of String)) As List(Of String) l.Sort(New NaturalStringComparer()) Return l End Function ' array version  Function ToNaturalSort(a As String()) As String() Array.Sort(a, New NaturalStringComparer()) Return a End Function 

El uso ahora es aún más fácil:

 Dim files = Directory.EnumerateFiles(your_path). Select(Function(s) Path.GetFileName(s)). ToList. ToNaturalSort() ' or without the path stripping: Dim files = Directory.EnumerateFiles(your_path).ToList.ToNaturalSort()