Tri intelligent comme Windows [Résolu]

Messages postés
375
Date d'inscription
mardi 1 juillet 2003
Dernière intervention
5 juin 2018
- - Dernière réponse : Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
- 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
Afficher la suite 

Votre réponse

3 réponses

Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
0
Merci
Bonsoir, qu'appelles tu
un tri comme le fait Windows dans l'explorateur
, trier pas nom? par date? par type? etc???
NHenry
Messages postés
14325
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
18 décembre 2018
-
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
...
Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
-
Ha oui aussi
MicDundee
Messages postés
375
Date d'inscription
mardi 1 juillet 2003
Dernière intervention
5 juin 2018
-
Oui c'est exactement ce que je cherche.
NHenry
Messages postés
14325
Date d'inscription
vendredi 14 mars 2003
Statut
Modérateur
Dernière intervention
18 décembre 2018
-
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.
MicDundee
Messages postés
375
Date d'inscription
mardi 1 juillet 2003
Dernière intervention
5 juin 2018
-
Autrement dit, ce n'est pas demain la veille pourtant beaucoup de programmes le font.
Commenter la réponse de Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
0
Merci
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.

MicDundee
Messages postés
375
Date d'inscription
mardi 1 juillet 2003
Dernière intervention
5 juin 2018
-
Tu n'en approches mais ce n'est pas encore cela.
        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("été")
        images.Add("ete")
        images.Add("(fichier 3")
        images.Add("a file9")
        images.Add("a file 4")
        Dim TriIntermedaires = (
                From s In images
                Let m = System.Text.RegularExpressions.Regex.Match(s, "(?<debut>[^\d]+)?(?<numero>\d+)")
                Select New With
                    {
                    Key .Texte = s,
                    Key .Debut = If(m.Success, m.Groups("debut").Value, s),'début du texte jusqu'au nombre ou le texte entier si pas de nombre
                    Key .Cle2Tri = If(m.Success, Convert.ToInt32(m.Groups("numero").Value), Integer.MaxValue) 'clé sur les chiffres
                    }
                    ).OrderBy(Function(x) x.Debut).ThenBy(Function(x) x.Cle2Tri).ToList()

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


Trié :
32 fichier test
(fichier 3
a file9
a file 4
ete
été
fichier 1
fichier 10
fichier 21 test
fichier 51 et aussi 14
fichier sans nombre

Windows tri comme ça :
(fichier 3
32 fichier test
a file 4
a file9
ete
été
fichier 1
fichier 10
fichier 21 test
fichier 51 et aussi 14
fichier sans nombre

(fichier 3 et a file9 ne sont pas à la bonne place. :( Pour les caractères spéciaux ça marche bien.
Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
-
quels caractères "spéciaux" es tu susceptible de rencontrer et dans quel ordre les veux tu?
MicDundee
Messages postés
375
Date d'inscription
mardi 1 juillet 2003
Dernière intervention
5 juin 2018
-
Les parenthèse et les crochets. Mais il y a le fameux fichier a file9 qui ne se place pas bien. :( Merci pour ton aide.
Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
-
a file9 c’est pas un probleme, les parenthèses et les crochets en revanche je ne sais pas encore comment faire.
Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
-
Et je suppose que s'ils sont dans le cours du texte c'est important aussi que le tri soit dans le même ordre que l'explorateur
Commenter la réponse de Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
0
Merci
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.
vb95
Messages postés
1735
Date d'inscription
samedi 11 janvier 2014
Statut
Contributeur
Dernière intervention
18 décembre 2018
> MicDundee
Messages postés
375
Date d'inscription
mardi 1 juillet 2003
Dernière intervention
5 juin 2018
-
Bonsoir !
Sans certitude : en mettant le tiret dans les caractères spéciaux cela donne quoi ?
Dim speciaux() As Char = {"("c, ")"c, "["c, "]"c, " "c, "-"c}
Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
-
Au risque de me repeter
Si un cas non prévu (et y'en a) se présente, il y aura une erreur
Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
-
Donc j'ai bien pris le temps de relire le sujet.
Dans tes exemples, il n'a jamais été question de -, donc je ne l'ai pas traité.
Microsoft a choisi de trier les noms de fichier dans l'explorateur selon une règle qui lui est propre.
Il faut donc tester où se situe tel ou tel caractère dans l'ordre de Microsoft.
Si on se limite aux caractères ASCII, il y a en 256 http://table-ascii.com
Je ne me suis pas amusé à vérifié chacun dans le tri de Microsoft.
C'est pourquoi j'ai mis cette erreur.
A chaque fois que tu la rencontreras, il faudra que tu fasses un test, pour savoir comment doit être trié ce caractère.
S'il doit être placé avec les parenthèses et les crochets et dans l'ordre "naturel" de tri des ces caractères, alors la solution de vb95 est la bonne, mais s'il va (par exemple) entre les Majuscules et les Minuscules c'est un autre code.
Je t'ai donné une solution toute faite avec les exemples que tu voulais, pour les autres cas, à toi de trouver et d'appliquer la loi de tri.
MicDundee
Messages postés
375
Date d'inscription
mardi 1 juillet 2003
Dernière intervention
5 juin 2018
-
Oui, en mettant ce que VB95 dit, c'est vrai le tri semble bon. Mais il y a un autre hic. Les caractères é ê è ne sont pas considérés comme les e. Je veux dire :

Trié par MS :
Gambie
Géorgie
Ghana

Par la classe :
Gambie
Ghana
Géorgie
Whismeril
Messages postés
12421
Date d'inscription
mardi 11 mars 2003
Dernière intervention
18 décembre 2018
-
Là ce qu’il faut faire, c’est enlever les signes diacritiques (accents, cédille, ce truc là į etc.) des lettres au moment du test.
VB95 a posté un code source qui le fait sur une string entière, caractère par caractère, il te suffit de faire le même traitement pour un caractère
http://codes-sources.commentcamarche.net/source/101763-remplacer-caracteres-accentuees-dans-une-chaine

Plus d’infos
https://fr.m.wikipedia.org/wiki/Diacritique
Commenter la réponse de Whismeril

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.