Relance post Trier les feuilles d'un classeur

Bonjour à toutes et tous,

J'aurais voulu appliquer en partie à mon fichier test (ci joint) le code du post "Trier les feuilles d'un classeur" de de de forum

https://forum.excel-pratique.com/viewtopic.php?forum_uri=excel&t=73626&start=/

Malgré beaucoup de temps a essayer de comprendre le code et de le modifier pour répondre à mon besoin je suis dans l'impasse.

Pourriez m'aider ou me proposer une autre solution ?

Merci

Cordialement

Hugues

Le code du post initial :

Option Base 1
Sub ClassementAlphaNumerique()
Application.ScreenUpdating = False

Dim sh As Worksheet, aa As Worksheet, bb As Worksheet
Dim sn As String, zz As String
Dim nbS As Integer, d As Integer
Dim c As Byte
Dim Tablo() As Variant

nbS = Sheets.Count
ReDim Tablo(nbS, 2)

'Split du nom de l'onglet
For Each sh In Worksheets
    sn = sh.Name
    zz = Mid(sn, Len(sn), 1)
    Do While IsNumeric(zz) 'boucle à partir du dernier caractère
        c = c + 1
        If c = Len(sn) Then Exit Do 's'il n'existe pas de valeur alphabétique
        zz = Mid(sn, Len(sn) - c, 1)
    Loop
    d = d + 1
    Tablo(d, 1) = Mid(sn, 1, Len(sn) - c) 'affectation de la partie alphabétique
    Tablo(d, 2) = (Mid(sn, Len(sn) - c + 1, Len(sn))) 'affectation de la partie numérique
    c = 0
Next sh

For a = LBound(Tablo) To UBound(Tablo)
    Set aa = Sheets(Tablo(a, 1) & Tablo(a, 2)) 'reconstitution du nom de l'onglet à partir des valeurs du tablo - Référence
    For b = a + 1 To UBound(Tablo)
        Set bb = Sheets(Tablo(b, 1) & Tablo(b, 2)) 'Cible

        If UCase(Tablo(a, 1)) > UCase(Tablo(b, 1)) Then 'classement des onglets de valeurs alphabétiques différentes, exp : AA1 et BBC

            routine Tablo(a, 1), Tablo(a, 2), Tablo(b, 1), Tablo(b, 2), aa, bb, b

        ElseIf UCase(Tablo(a, 1)) = UCase(Tablo(b, 1)) _
        And Val(Tablo(a, 2)) = Val(Tablo(b, 2)) _
        And Len(Tablo(a, 2)) < Len(Tablo(b, 2)) Then 'classement des onglets de même valeur numérique mais de formats différents, exp : 1 et 01

            routine Tablo(a, 1), Tablo(a, 2), Tablo(b, 1), Tablo(b, 2), aa, bb, b

        ElseIf UCase(Tablo(a, 1)) = UCase(Tablo(b, 1)) _
        And Val(Tablo(a, 2)) > Val(Tablo(b, 2)) Then 'classement des onglets de valeur même valeur alphabétique mais de valeurs numériques différentes,exp : AA1 et AA8

            routine Tablo(a, 1), Tablo(a, 2), Tablo(b, 1), Tablo(b, 2), aa, bb, b
        End If
    Next b
Next a

End Sub

Sub routine(ta1, ta2, tb1, tb2, aa, bb, b)

'tri du Tablo
Temp1 = ta1
Temp2 = ta2
ta1 = tb1
ta2 = tb2
tb1 = Temp1
tb2 = Temp2

'déplacement des onglets et réaffectation des variable aa et bb
bb.Move before:=aa
Set aa = bb

Set bb = Sheets(tb1 & tb2)
bb.Move after:=Sheets(b) 'l'onglet Référence initial prend la place d'onglet Cible afin que l'ordre des onglets soit synchro avec les infos du tablo
End Sub

Bonsoir,

Je n'ai pas lu ta procédure, mais elle m'a parue un peu longue !

Je te propose donc une autre procédure, visiblement plus courte, et fort simple à mon sens.

Sub TriFeuilles()
    Dim ff(), i%, j%
    ReDim ff(Worksheets.Count)
    For i = 1 To Worksheets.Count
        ff(i) = Worksheets(i).Name
    Next i
    For i = 1 To UBound(ff) - 1
        For j = i + 1 To UBound(ff)
            If ff(j) < ff(i) Then
                ff(0) = ff(j): ff(j) = ff(i): ff(i) = ff(0)
            End If
        Next j
    Next i
    Application.ScreenUpdating = False
    For i = UBound(ff) To 1 Step -1
        Worksheets(ff(i)).Move before:=Worksheets(1)
    Next i
End Sub

On recueille les noms des feuilles dans un tableau, on trie le tableau, puis on le parcourt de la fin vers le début, en déplaçant systématiquement la feuille indiquée à la première place, et à la fin elles sont triées. On aurait pu faire l'inverse (parcourir du début à la fin et déplacer en queue) pour le même résultat, mais ça m'est venu ainsi, et Worksheets(1) est plus court à écrire !

NB- Si tu as mis Option Base 1 en option dans ton classeur, tu le supprimes, tu aurais une erreur ! Je ne travaille jamais avec cette option, toujours avec base 0 par défaut, et mon tableau a un indice 0 utilisé.

Cordialement.

Bonjour Mferrand, Bonjour à toutes et tous,

Mferrand, merci pour ton retour.

Mais malheureusement ton code n'est pas efficient.

Il faut dire que les noms de mes onglets de classeur ont un format un peu particulier (cf mon classeur exemple, je les importe comme cela sans pouvoir les modifier d'un logiciel tiers). C'est du texte (formater standard dans mes cellules excel).

Exemple de quelque valeurs contenues dans mon fichier

Semaine :

SEM 53 2015

SEM 1 2016

SEM 2 2016

SEM 3 2016

SEM 4 2016

SEM 37 2018

SEM 38 2018

SEM 39 2018

SEM 40 2018

Mois :

janvier 2015

février 2015

mars 2015

juillet 2015

août 2015

août 2019

septembre 2019

octobre 2019

janvier 2020

février 2020

C'est pourquoi il est difficile à mon avis d'établir les règles qui me conviendraient sur un classement alpha numérique, mes données à classer contiennent un mix de texte et de nombre. Sachant qu'en plus je voudrai s avoir toutes les feuilles semaine triées devant toutes les feuilles mois triées à leur tour. (exemple : SEM 53 2015, SEM 1 2016, SEM 2 2016,SEM 3 2016, SEM 4 2016, SEM 37 2018, SEM 38 2018, SEM 39 2018, SEM 40 2018, janvier 2015, février 2015, mars 2015, juillet 2015, août 2015, août 2019, septembre 2019, octobre 2019 janvier 2020, février 2020).

Ton approche me donne une idée, ne serait t'il pas possible de trier les onglets en fonction d"un index (mon classeur contient une liste des semaines et des mois triée tel que je le veux, cf colonne A et B feuille LISTE de mon classeur exemple) ?

NB- Si tu as mis Option Base 1 en option dans ton classeur, tu le supprimes, tu aurais une erreur ! Je ne travaille jamais avec cette option, toujours avec base 0 par défaut, et mon tableau a un indice 0 utilisé.

Concernant ce point et simplement pour info si on ne part plus sur ce code initial, même si le tri obtenu ne correspond pas à mes attentes le code repris tel que en test avec Option Base 1 fonctionnait sans message d'erreur. Maintenant j'en apprend tous les jours sur VB je ne connaissais pas du tout cet élément d'option des indices de tableau.

Merci

Cordialement

Hugues

Bonjour,

J'ai fourni un classement des feuilles par ordre alpha... ce qui m'avait semblé être demandé !

D'après ce que tu indiques tu as des feuilles semaines commençant par SEM : forme SEM num année.

A classer en ordre chonologique.

Et des feuilles mois : NomMois année. A classer également dans l'ordre chronologique.

Mais qu'en est-il du classement relatif de ces deux catégories ?

Pour ce qui est de l'Option Base, le problème est qu'on peut toujours transférer une macro réutilisable, et l'option n'étant pas au niveau procédure avoir des surprises. Avec l'option par défaut on sait ce qu'il en est : l'indice minimal est 0, l'indice max celui qu'on indique, et si on veut un autre indice min que 0 on l'indique aussi [ 1 To 10, 3 To 23, -10 To 10...) Quant aux tableaux constitués par affectation des valeurs d'une plage, on sait qu'ils sont toujours d'indice 1 minimal et à 2 dimensions.

Si j'appelle l'élément d'indice 0 d'un tableau et que tu es sous option base 1, le tableau n'a pas d'indice 0, tu auras une erreur 9... dans un cas où il n'y a pas d'appel direct d'un indice absent, pas d'erreur mais tu peux avoir d'autres surprises dans les résultats...

NB-Dans un cas comme celui-ci où je mets des éléments dans un tableau en vue de les trier, je place mes éléments à trier de 1 à fin et je me sers de l'élément 0 pour le switch lors du tri (évitant l'appel à une autre variable).

Pour ton tri de feuilles, je maintiens le principe de la méthode : tableau mis en ordre à partir duquel on reclasse l'ensemble. La seule chose à modifier c'est la mise en ordre, à préciser...

Cordialement.

Bonjour Mferrand,

Merci de t'impliquer une fois de plus dans un de mes sujets.

Je précise que même si je progresse notamment grâce à tes conseils, ceux des autres membres du forum et ma curiosité, dés qu'il s'agit de sortir des fonctions basiques de VB j'atteint vite la limite de mes connaissances et de mes compétences. Notamment quand j'essaye d'adapter et de m'inspirer de code existant.

Ainsi si je te cite :

J'ai fourni un classement des feuilles par ordre alpha... ce qui m'avait semblé être demandé !

D'après ce que tu indiques tu as des feuilles semaines commençant par SEM : forme SEM num année.

A classer en ordre chonologique.

Et des feuilles mois : NomMois année. A classer également dans l'ordre chronologique.

Mais qu'en est-il du classement relatif de ces deux catégories ?

Oui ce qui précède est exact et j'ai bien des feuilles à triées de 2 types :

- Semaine exemple : SEM 53 2015, elles commencent toujours par "SEM" puis le numéro de semaine "53" (1; 2; 10; 8; 20; etc....) et enfin l'année 2015 (2016; 2017; 2018; ETC....)

classement souhaité chronologique selon cette logique :

si j'ai : SEM 52 2016, SEM 2 2016, SEM 4 2017, SEM 14 2016, SEM 53 2015

alors classement : SEM 53 2015, SEM 2 2016, SEM 14 2016, SEM 52 2016, SEM 4 2017

- Mois exemple : décembre 2015, ces feuilles commencent toujours par un nom de mois (janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre) puis l'année 2015.

classement souhaité chronologique selon cette logique :

si j'ai : mars 2016, janvier 2016, décembre 2017, septembre 2016, décembre 2015

alors classement : décembre 2015, mars 2016, janvier 2016, septembre 2016, décembre 2017

Classement relatif de ces 2 catégories si je comprend bien ta question:

Une fois le tri ci dessus effectué, il faudrait avoir les semaine triées avant les mois triés soit sur la base des exemples ci dessus :

SEM 53 2015, SEM 2 2016, SEM 14 2016, SEM 52 2016, SEM 4 2017, décembre 2015, mars 2016, janvier 2016, septembre 2016, décembre 2017.

Peux tu m'expliquer un peu plus ton code ci après, je n'arrive pas bien à saisir comment tu traduis dans ton code classement alpha par exemple :

Sub TriFeuilles()
    Dim ff(), i%, j%
    ReDim ff(Worksheets.Count)
    For i = 1 To Worksheets.Count
        ff(i) = Worksheets(i).Name
    Next i
    For i = 1 To UBound(ff) - 1
        For j = i + 1 To UBound(ff)
            If ff(j) < ff(i) Then
                ff(0) = ff(j): ff(j) = ff(i): ff(i) = ff(0)
            End If
        Next j
    Next i
    Application.ScreenUpdating = False
    For i = UBound(ff) To 1 Step -1
        Worksheets(ff(i)).Move before:=Worksheets(1)
    Next i
End Sub

Merci

Cordialement

Hugues

Bon ! ma réponse est passée à la trappe ! Rupture réseau de plusieurs minutes et qui s'est révélée plus longue pour Excel-Pratique que pour d'autres !

Je recommence avec précaution. Ce bout de code constitue la procédure de tri du tableau :

    For i = 1 To UBound(ff) - 1
        For j = i + 1 To UBound(ff)
            If ff(j) < ff(i) Then
                ff(0) = ff(j): ff(j) = ff(i): ff(i) = ff(0)
            End If
        Next j
    Next i

Lorsqu'on compare deux éléments du tableau :

            If ff(j) < ff(i) Then

on teste si le second placé(j) est inférieur au premier placé (i). Si c'est le cas il doit passer avant et donc on intervertit les deux...

S'agissant de texte, la comparaison se fait sur les caractères, ce qui respecte l'ordre alphabétique (plus exactement, étant par défaut en Option Compare Binary, la comparaison se fait sur les codes binaires des caractères, ce qui différencie la casse, mais ce problème n'étant pas posé, le résultat obtenu correspond à l'ordre alpha, les chiffres précédant les lettres).

Pour ton classement, je vois ce qu'il en est. Tu confirmes qu'il n'y a pas d'autres feuilles que semaines et mois, qui devront occuper le cas échéant une place à définir.

Cordialement.

Re,

Voilà un tri chrono selon tes noms de feuilles :

Sub TriChronoFeuilles()
    Dim ff(), i%, j%, k%, nf
    ReDim ff(Worksheets.Count, 1)
    For i = 1 To Worksheets.Count
        ff(i, 0) = Worksheets(i).Name
    Next i
    For i = 1 To UBound(ff)
        nf = Split(ff(i, 0))
        If UBound(nf) > 0 Then
            If nf(0) = "SEM" Then
                If UBound(nf) = 2 Then
                    ff(i, 1) = "a" & nf(2) & Format(nf(1), "00")
                Else
                    ff(i, 1) = "c" & ff(i, 0)
                End If
            Else
                For j = 1 To 12
                    If MonthName(j) = nf(0) Then
                        ff(i, 1) = "b" & nf(1) & Format(j, "00"): Exit For
                    End If
                Next j
                If j > 12 Then ff(i, 1) = "c" & ff(i, 0)
            End If
        Else
            nf(i, 1) = "c" & nf(i, 0)
        End If
    Next i
    For i = 1 To UBound(ff) - 1
        For j = i + 1 To UBound(ff)
            If ff(j, 1) < ff(i, 1) Then
                For k = 0 To 1
                    ff(0, k) = ff(j, k): ff(j, k) = ff(i, k): ff(i, k) = ff(0, k)
                Next k
            End If
        Next j
    Next i
    Application.ScreenUpdating = False
    For i = UBound(ff) To 1 Step -1
        Worksheets(ff(i, 0)).Move before:=Worksheets(1)
    Next i
End Sub

Le code suppose que les normes de composition des noms soient respectées :

  • SEM en majuscules
  • les noms des mois conformes à la liste des noms de mois figurant par défaut dans les classeurs et correspondant aux normes régionales (en FR, les noms sont en minuscules, j'espère que MAC n'y déroge pas ! Tu peux consulter la liste dans les options > Options avancées > Modifier les listes personnalisées (à la fin) : c'est normalement la dernière liste par défaut et MonthName renvoie des noms conformes à cette liste).
  • les espaces prévues...
J'ai pris la précaution de tests élémentaires pour les cas où la correspondance ne serait pas assurée, les feuilles concernées seront rejetées à la fin, ce qui permettra de vérifier et rectifier les noms : espaces oublées ou omises, noms autres... mais il peut toujours y avoir un cas totalement imprévu qui échappe aux tests et déclenche une erreur... !

Cordialement.

Bonjour Mferrand

Tout d'abord merci beaucoup, ensuite bravo et enfin encore une fois merci.

En effet mes premiers tests confirment que ton code correspond à 100% de mes besoins, et oui aussi sur ma version Excel MAC.

Et s'il devait y'avoir quelques rares exceptions (effectivement on est pas à l'abri, même si en amont ma procédure d'importation de la base et censée formater les libellées semaine et mois tel que voulu par ton code), vu le temps que tu me fais gagner, corriger quelques feuilles à la volée manuellement ne serait pas rédhibitoire.(sachant qu'après un premier test sur copie de ma base réelle, je n'ai constaté aucunes erreurs).

Et je te félicite aussi pour la réactivité tant sur la compréhension de mon besoin que la réponse très rapide que tu y apporte, je n'ose imaginer ce que cela aurait été sans cette petite coupure réseau (Mferrand invente la vitesse de la lumière sur EXCEL )

Je vais maintenant décortiquer plus en approfondi ton code pour parfaire mes connaissances.

Sur ce point j'ai du modifier une partie du code qui générait une erreur (déboge recquis à l'exécution de la macro) sans que je n'ai réellement compris pourquoi.

J'ai condamné à l'exécution ceci

nf(i, 1) = "c" & nf(i, 0)

dans la partie ci après de la procédure :

For j = 1 To 12
                    If MonthName(j) = nf(0) Then
                        ff(i, 1) = "b" & nf(1) & Format(j, "00"): Exit For
                    End If
                Next j
                If j > 12 Then ff(i, 1) = "c" & ff(i, 0)
            End If
        Else
           'nf(i, 1) = "c" & nf(i, 0)
        End If

Merci

Cordialement

Hugues

Re,

Je suis plutôt lent ! mais j'arrive parfois à donner le change...

Là j'ai été un peu trop vite : j'ai tapé nf au lieu de ff !

            ff(i, 1) = "c" & ff(i, 0)

Voilà la bonne ligne, elle figure 3 fois, c'est destiné à écarter les feuilles aux noms non conformes. La 3e fois j'ai dérapé...

Par contre, si elle t'a déclenchée une erreur c'est que l'exécution est passée par là, donc une feuille dont le nom ne comportait pas d'espace...

La structure de la procédure est en gros la même, mais on a ajouté une colonne au tableau, et une étape intermédiaire pour remplir cette colonne.

[AAAA=année, SS=num semaine, MM=num mois]

On traduit le nom dans cette 2e colonne par :

aAAAASS pour les feuilles semaine

bAAAAMM pour les feuilles mois

cNomFeuille pour les autres s'il y a lieu (ou feuilles dont noms non normalisés)

On peut ainsi appliquer un tri sur cette colonne qui produira le classement voulu.

Cordialement.

Bonjour Mferrand,

Merci pour ta contribution, mon besoin est définitivement traité comme je le voulais.

Merci également pour tes explications.

J'ai modifié légèrement le code pour écarter du tri les 3 premières feuilles qui sont des onglets d' explications, paramétrage et import des données.

En écrivant ceci :

For i = 4 To UBound(ff)

Mis à part cela j'ai repris l'intégralité de ton code.

Bravo et merci.

Cordialement

Hugues

Oui ça marche dans le cas particulier, car en les laissant en tête de liste lors du tri de tableau elles sont ramenées à leur place lors du tri de feuilles... Subtilement raisonné !

Sinon pour t'ôter tout souci ultérieur, tu définis leur emplacement et leur ordre, et on les dote d'un "code" qui les placera à l'emplacement voulu. Mais bon ! cela revient au même tant que tu les veux en tête, mais si l'emplacement change, ou s'il y a d'autres feuilles... cela reste une solution.

Cordialement.

Rechercher des sujets similaires à "relance post trier feuilles classeur"