Tri intelligent comme Windows

Résolu
Utilisateur anonyme - 15 mars 2018 à 17:48
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 - 1 avril 2018 à 07:58
Bonjour,
en VB 2015, est-il possible de faire un tri comme le fait Windows dans l'explorateur ? C'est embêtant de ne pas avoir le même tri entre Windows et VB.
J'utilise :
Public Images As New List(Of String)
Images.Sort()
Merci

3 réponses

Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
15 mars 2018 à 18:03
Bonsoir, qu'appelles tu
un tri comme le fait Windows dans l'explorateur
, trier pas nom? par date? par type? etc???
0
NHenry Messages postés 15112 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 13 avril 2024 159
15 mars 2018 à 18:11
Je suspect que c'est du genre :
Image 1
Image 2
Image 3
...
Image 10
Image 11

Contrairement à un ordre alphabétique qui ferai :
Image 1
Image 10
Image 11
Image 2
...
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
15 mars 2018 à 18:39
Ha oui aussi
0
Utilisateur anonyme
15 mars 2018 à 19:32
Oui c'est exactement ce que je cherche.
0
NHenry Messages postés 15112 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 13 avril 2024 159
15 mars 2018 à 20:23
Ce type de tri est assez complexe à mettre en place, et je pense qu(il faut déjà étudier les cas possibles ("10image", ima10ge", "image10", ...), c'est tout un sujet.
0
Utilisateur anonyme
15 mars 2018 à 20:39
Autrement dit, ce n'est pas demain la veille pourtant beaucoup de programmes le font.
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
15 mars 2018 à 22:36
Si c'est possible,
  • il faut extraire le nombre, où qu'il se trouve (avec une regex par exemple),
  • le convertir en entier pour pouvoir trier,
  • créer une liste intermédiaire avec le texte d'origine et notre entier
  • trier la liste intermédiaire
  • en ressortir une liste avec les textes d'origine.


        Dim images As New List(Of String)

        images.Add("fichier 51 et aussi 14")
        images.Add("fichier sans nombre")
        images.Add("fichier 10")
        images.Add("fichier 21 test")
        images.Add("32 fichier test")
        images.Add("fichier 1")
        images.Add("fichier 2")
        images.Add("fichier 3")
        images.Add("fichier 4")

        Dim imagesIntermedaires = (
                From s In images
                Let m = Regex.Match(s, "(?<numero>\d+)")
                Select New With {Key .Texte = s, Key .Cle2Tri = If(m.Success, Convert.ToInt32(m.Groups("numero").Value), Integer.MaxValue)}).OrderBy(Function(x) x.Cle2Tri).ToList()

        Dim imagesTriees As List(Of String) = imagesIntermedaires.Select(Function(x) x.Texte).ToList()
        'si besoin
       images = imagesTriees


S'il y a 2 nombres c'est le premier qui compte, s'il n'y en a pas, c'est mis à la fin.

0
Utilisateur anonyme
16 mars 2018 à 22:31
Bonjour ! Ca marche mais pas tout à fait. Voici la liste triée :
fichier 1
fichier 2
fichier 3
fichier 4
fichier 10
fichier 21 test
32 fichier test
fichier 51 et aussi 14
fichier sans nombre

32 fichier test n'est pas au bon endroit. :(
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
16 mars 2018 à 23:22
Ben si il est entre 21 et 51.
0
Utilisateur anonyme
17 mars 2018 à 10:01
Non, Windows le place au début parce qu'il commence par un chiffre et non une lettre. J'ai renommé les fichiers selon les exemples. 32 fichier test est le premier.
0
NHenry Messages postés 15112 Date d'inscription vendredi 14 mars 2003 Statut Modérateur Dernière intervention 13 avril 2024 159
17 mars 2018 à 12:44
Petit rappel, on ne fourni pas un code "prêt à l'emploi", il te faut savoir adapter un peu les codes fournis.
Ce n'est que comme ça que tu t'améliorera.
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
17 mars 2018 à 19:00
Et puis besoin mal décrit, réponse approximative....
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
18 mars 2018 à 23:17
J'ai créé une classe dédiée.
Si un cas non prévu (et y'en a) se présente, il y aura une erreur
Imports System
Imports System.Linq
Imports System.Text.RegularExpressions

''' <summary>
''' Ton besoin étant plus compliqué qu'il n'y parraissait initialement
''' je crée une classe dédiée, elle implémente IComparable, interface utlisée par la métode Sort()
''' </summary>
Public Class TriMicDundee
    Implements IComparable(Of TriMicDundee)

    Public Sub New(ByVal LeTexte As String)
        Texte = LeTexte
    End Sub

    Public Property Texte() As String

    ''' <summary>
    ''' Retourne un entier décrivant la comparaison entre cette instance et une autre.
    ''' 0 c'est égal
    ''' positif cette occurence est "plus grande", sera triée en direction de la fin de la liste
    ''' négatif cette occurence est "plus petite", sera triée en direction du début de la liste
    ''' </summary>
    ''' <param name="other"></param>
    ''' <returns></returns>
    Private Function CompareTo(ByVal other As TriMicDundee) As Integer Implements IComparable(Of TriMicDundee).CompareTo
        'on commence par le cas "fichier 2" et "fichier     10"
        Dim r As New Regex("^(?<debut>[^\d]+)?(?<numero>\d+)")
        Dim m1 As Match = r.Match(Texte)
        Dim m2 As Match = r.Match(other.Texte)
        If m1.Success AndAlso m2.Success AndAlso m1.Groups("debut").Value.TrimEnd(" "c) = m2.Groups("debut").Value.TrimEnd(" "c) Then
            Return Integer.Parse(m1.Groups("numero").Value).CompareTo(Integer.Parse(m2.Groups("numero").Value))
        End If

        Dim nbreCaractereATester As Integer = Math.Min(Texte.Length, other.Texte.Length) 'on va comparer caractère par caractère

        Dim speciaux() As Char = {"("c, ")"c, "["c, "]"c, " "c}

        For i As Integer = 0 To nbreCaractereATester - 1
            Dim moi As Char = Texte.Chars(i)
            Dim autre As Char = other.Texte.Chars(i)

            If moi = autre Then 'même caractère, pas de comparaison possibble => itération suivante
                Continue For
            End If

            If moi = "."c Then 'on arrive à l'extension, ce moi est plus court, c'est lui qui vaut -1, attention, on fait l'hypotèse qu'il n'y a qu'un seul. dans le nom de fichier
                Return 1
            End If

            If autre = "."c Then
                Return -1
            End If

            If Char.IsLetter(moi) AndAlso Char.IsLetter(autre) Then 'deux lettres différentes, on retourne la comparaison de base
                Return moi.CompareTo(autre)
            End If

            If speciaux.Contains(moi) AndAlso speciaux.Contains(autre) Then '2 spéciaux différents, on retourne la comparaison de base
                Return moi.CompareTo(autre)
            End If

            If Char.IsLetterOrDigit(moi) AndAlso speciaux.Contains(autre) Then 'moi n'est pas un spécial et autre si, la comparaison vaut 1
                Return 1
            End If

            If speciaux.Contains(moi) AndAlso Char.IsLetterOrDigit(autre) Then 'cas inverse à ci dessus
                Return -1
            End If

            If Char.IsLetter(moi) AndAlso Char.IsDigit(autre) Then 'moi est une lettre, autre un chiffre, la comparaison 1
                Return 1
            End If

            If Char.IsDigit(moi) AndAlso Char.IsLetter(autre) Then 'cas inverse à ci-dessus
                Return -1
            End If

            'si on arrive là, on est face à un cas non prévu => à coder donc
            Throw New Exception("Comparaison non codée")
        Next i

        'si la boucle se termine sans résultat, alors les 2 instances sont identiques
        Return 0
    End Function
End Class


Pour s'en servir
        Dim images As New List(Of String)()
        images.Add("fichier 51 et aussi 14.txt")
        images.Add("fichier sans nombre.txt")
        images.Add("fichier 10.txt")
        images.Add("fichier 21 test.txt")
        images.Add("32 fichier test.txt")
        images.Add("fichier.txt")
        images.Add("fichiers.txt")
        images.Add("fichier 1.txt")
        images.Add("fichier 2.txt")
        images.Add("fichier 2.csv")
        images.Add("(fichier 3.txt")
        images.Add("[fichier 3.txt")
        images.Add("]fichier 3.txt")
        images.Add(")fichier 3.txt")
        images.Add("a file        4.txt")
        images.Add("a file9.txt")
        images.Add("a file[9.txt")
        images.Add("6a file 4.txt")

        Dim intermediaires As List(Of TriMicDundee) = images.Select(Function(i) New TriMicDundee(i)).ToList()
        intermediaires.Sort()
        Dim imagesTriees As List(Of String) = intermediaires.Select(Function(x) x.Texte).ToList()


Pour ces noms de fichier le résultat est identique au tri de windows 10.
0
Utilisateur anonyme
20 mars 2018 à 17:16
Salut ! Merci pour cette classe. Je savais que ce n'était pas une mince affaire mon truc et je suis certaine que cela va intéresser d'autre que moi.
Pour les caractères spéciaux, ça marche et j'ai vu que tu avais testé les extensions. Bien vu.
Juste un truc qui ne colle pas encore (désolée). Un fichier s'appelle fichierstxt. Je ne sais pas si tu voulais écrire fichiers.txt mais il se trouve mal placé malheureusement. Il est avant fichier.txt. :(
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
20 mars 2018 à 19:23
Dans le code au dessus, il s'appelle bien fichiers.txt et pas fichierstxt.
Mais bon pour le coup, maintenant j'ai mis les 2.
Il y a bien une subtilité avec l'espace qui m'avait échappé.

J'ai mis la méthode de tri dans la classe, comme ça si tu dois faire plusieurs tris, tu n'auras qu'une ligne à coder.

Imports System
Imports System.Linq
Imports System.Text.RegularExpressions

''' <summary>
''' Ton besoin étant plus compliqué qu'il n'y parraissait initialement
''' je crée une classe dédiée, elle implémente IComparable, interface utlisée par la métode Sort()
''' </summary>
Public Class TriMicDundee
    Implements IComparable(Of TriMicDundee)

    Public Sub New(ByVal LeTexte As String)
        Texte = LeTexte
    End Sub

    Public Property Texte() As String

    ''' <summary>
    ''' Retourne un entier décrivant la comparaison entre cette instance et une autre.
    ''' 0 c'est égal
    ''' positif cette occurence est "plus grande", sera triée en direction de la fin de la liste
    ''' négatif cette occurence est "plus petite", sera triée en direction du début de la liste
    ''' </summary>
    ''' <param name="other"></param>
    ''' <returns></returns>
    Private Function CompareTo(ByVal other As TriMicDundee) As Integer Implements IComparable(Of TriMicDundee).CompareTo
        'on commence par le cas "fichier 2" et "fichier     10"
        Dim r As New Regex("^(?<debut>[^\d]+)?(?<numero>\d+)")
        Dim m1 As Match = r.Match(Texte)
        Dim m2 As Match = r.Match(other.Texte)
        If m1.Success AndAlso m2.Success AndAlso m1.Groups("debut").Value.TrimEnd(" "c) = m2.Groups("debut").Value.TrimEnd(" "c) Then
            Return Integer.Parse(m1.Groups("numero").Value).CompareTo(Integer.Parse(m2.Groups("numero").Value))
        End If

        Dim nbreCaractereATester As Integer = Math.Min(Texte.Length, other.Texte.Length) 'on va comparer caractère par caractère

        Dim speciaux() As Char = {"("c, ")"c, "["c, "]"c, " "c}

        For i As Integer = 0 To nbreCaractereATester - 1
            Dim moi As Char = Texte.Chars(i)
            Dim autre As Char = other.Texte.Chars(i)

            If moi = autre Then 'même caractère, pas de comparaison possibble => itération suivante
                Continue For
            End If

            If moi = "."c Then 'on arrive à l'extension, ce moi est plus court, c'est lui qui vaut -1, attention, on fait l'hypotèse qu'il n'y a qu'un seul. dans le nom de fichier
                If autre = " "c Then 'sauf si autre est un espace
                    Return 1
                End If
                Return -1
            End If

            If autre = "."c Then 'cas inverse à ci-dessus
                If moi = " "c Then
                    Return -1
                End If
                Return 1
            End If

            If Char.IsLetter(moi) AndAlso Char.IsLetter(autre) Then 'deux lettres différentes, on retourne la comparaison de base
                Return moi.CompareTo(autre)
            End If

            If speciaux.Contains(moi) AndAlso speciaux.Contains(autre) Then '2 spéciaux différents, on retourne la comparaison de base
                Return moi.CompareTo(autre)
            End If

            If Char.IsLetterOrDigit(moi) AndAlso speciaux.Contains(autre) Then 'moi n'est pas un spécial et autre si, la comparaison vaut 1
                Return 1
            End If

            If speciaux.Contains(moi) AndAlso Char.IsLetterOrDigit(autre) Then 'cas inverse à ci dessus
                Return -1
            End If

            If Char.IsLetter(moi) AndAlso Char.IsDigit(autre) Then 'moi est une lettre, autre un chiffre, la comparaison 1
                Return 1
            End If

            If Char.IsDigit(moi) AndAlso Char.IsLetter(autre) Then 'cas inverse à ci-dessus
                Return -1
            End If

            'si on arrive là, on est face à un cas non prévu => à coder donc
            Throw New Exception("Comparaison non codée")
        Next i

        'si la boucle se termine sans résultat, alors les 2 instances sont identiques
        Return 0
    End Function

    Public Shared Function TrierListe(Liste As List(Of String)) As List(Of String)
        Dim intermediaires As List(Of TriMicDundee) = Liste.Select(Function(i) New TriMicDundee(i)).ToList()
        intermediaires.Sort()
        Return intermediaires.Select(Function(x) x.Texte).ToList()
    End Function

End Class


Et pour s'en servir
        Dim images As New List(Of String)()
        images.Add("fichier 51 et aussi 14.txt")
        images.Add("fichier sans nombre.txt")
        images.Add("fichier 10.txt")
        images.Add("fichier 21 test.txt")
        images.Add("32 fichier test.txt")
        images.Add("fichier.txt")
        images.Add("fichiers.txt")
        images.Add("fichierstxt")
        images.Add("fichier 1.txt")
        images.Add("fichier 2.txt")
        images.Add("fichier 2.csv")
        images.Add("(fichier 3.txt")
        images.Add("[fichier 3.txt")
        images.Add("]fichier 3.txt")
        images.Add(")fichier 3.txt")
        images.Add("a file        4.txt")
        images.Add("a file9.txt")
        images.Add("a file[9.txt")
        images.Add("6a file 4.txt")

        Dim imagesTriees As List(Of String) = TriMicDundee.TrierListe(images)
0
Utilisateur anonyme
21 mars 2018 à 14:29
Merci beaucoup, là ça marche impeccable.
0
Whismeril Messages postés 19025 Date d'inscription mardi 11 mars 2003 Statut Contributeur Dernière intervention 19 avril 2024 656
21 mars 2018 à 17:50
De rien
0
Utilisateur anonyme
29 mars 2018 à 23:10
Salut ! Un petit souci. En fait, la classe rencontre une erreur lorsqu'elle trouve un tiret "-". Pourquoi ? Merci.
0
Rejoignez-nous