Boucle de remplacement

Bonjour le forum

Je ne gère pas du tout les boucles et j'ai un petit soucis de mise en place de ma boucle.

J'ai une macro qui me cherche des en-têtes d'une feuille, pour mes les coller dans l'ordre que je veux sur une autre feuille.

Actuellement je fait ainsi :

Dim searchrange As Range
           Dim fd4 As Range
                       Set searchrange = Range("A1", Range("A400").End(xlToRight))
                       Set fd4 = searchrange.Find("Numéro", LookIn:=xlValues, lookat:=xlWhole)
                       ZZ = fd4.Column
                       Columns(ZZ).Cut
                           Sheets("Origine").Select
                               Columns("A:A").Insert Shift:=xlToRight
                           Sheets("Inscrits").Select

Je copie ce code X fois et j'écris à la main "fd4", fd5, fd6 etc, et l'adresse de colonne A:A, B:B, C:C etc.

Je suis persuadé qu'une boucle serait plus adaptée mais je ne sais pas comment la construire.

Une boucle for se ferait genre comme ça je suppose :

For i = 1 To jesaispasencore
Dim searchrange As Range
           Dim fd As Range
                       Set searchrange = Range("A1", Range("A400").End(xlToRight))
                       Set fd = searchrange.Find("Numéro", LookIn:=xlValues, lookat:=xlWhole)
                       ZZ = fd.Column
                       Columns(ZZ).Cut
                           Sheets("Origine").Select
                               Columns(i).Insert Shift:=xlToRight
                           Sheets("Inscrits").Select
Next

MAIS MON SOUCIS SUPPLEMENTAIRE, c'est qu'à chaque i j'ai une valeur de recherche qui change. ça ne sera pas que numéro, il y aura aussi derriere le nom, le prénom, le sexe, ville etc etc etc

Comment construire ça svp, help.

Merciii

Bonjour,

Une suggestion :

Sub CeQueTuVeuxFaire()
    Dim fd As Range, searchrange As Range, searchitems, i%, er%
    Dim wsI As Worksheet, wsO As Worksheet
    Set wsI = Sheets("Inscrits")
    Set wsO = Sheets("Origine")
    searchitems = Split("Numéro;Nom;Prénom;Ville;Adresse;Autre1;Autre2", ";")
    For i = 0 To UBound(searchitems)
        Set searchrange = wsI.Range("A1", wsI.Range("A400").End(xlToRight))
        Set fd = searchrange.Find(searchitems(i), , xlValues, xlWhole)
        If Not fd Is Nothing Then
            wsI.Columns(fd.Column).Cut
            wsO.Columns(i + 1 - er).Insert xlShiftToRight
        Else
            er = er + 1
        End If
    Next i
End Sub

Remarques sur le code :

  • Déclaration de toutes les variables, et en-tête de procédure...
  • 2 variables Worksheet pour les deux feuilles : faciliter l'écriture en qualifiant les plages (et supprimant corrélativement les Select).
  • Une variable (type Variant) pour y lister dans l'ordre les libellés cherchés successivement (en utilisant Split...)
  • Boucle de 0 (indice mini) à l'indice max du tableau des libellés cherchés.

- Affectation searchrange (inchangée)...

NB- Je ne vois pas l'utilité du "A400", les libellés étant en ligne 1, et ensuite tu coupes la colonne entière...

Je l'ai laissée car si le nombre de lignes est commun sur Inscrits et Origine (ce qui n'est pas précisé), on pourrait ne couper et insérer que la partie utile de la colonne... On définit la colonne dans searchrange (ce qui la délimitera) et on insère sur une plage équivalente de 400 lignes...

- Quand on utilise Find, il est toujours souhaitable de vérifier que la recherche est fructueuse...

On peut ainsi poursuivre la procédure si elle ne l'était pas. Mais dans ce cas on provoquerait un décalage dû à la non insertion de colonne. Donc pour l'éviter, dans le cas d'une erreur éventuelle, on incrémente une variable (variable qui indique donc le nombre de colonnes éventuellement manquantes) que l'on déduira à l'insertion pour que celle-ci se fasse sur la bonne colonne. Si tout se passe sans erreur, la valeur de cette variable restera à 0.

- L'insertion se fait sur la colonne i+1 (i=0 pour le premier libellé...) et comme vu ci-dessus on diminue ce numéro de colonne de la variable er au cas où une insertion ait été loupée (ex.: on insère la 1re colonne trouvé en colonne A, on a une erreur sur la 2e qui n'est pas insérée, la variable er prend la valeur 1, la 3e aurait été insérée en C (sans correctif), laissant en B une colonne inadéquate, en faisant jouer er on l'insère en B : il manquera une colonne entre A et B mais on n'aura pas de fausse colonne à déplacer, on rétablira donc plus vite la situation ensuite).

Cordialement.

MFerrand a écrit :

Bonjour,

Une suggestion :

Sub CeQueTuVeuxFaire()
    Dim fd As Range, searchrange As Range, searchitems, i%, er%
    Dim wsI As Worksheet, wsO As Worksheet
    Set wsI = Sheets("Inscrits")
    Set wsO = Sheets("Origine")
    searchitems = Split("Numéro;Nom;Prénom;Ville;Adresse;Autre1;Autre2", ";")
    For i = 0 To UBound(searchitems)
        Set searchrange = wsI.Range("A1", wsI.Range("A400").End(xlToRight))
        Set fd = searchrange.Find(searchitems(i), , xlValues, xlWhole)
        If Not fd Is Nothing Then
            wsI.Columns(fd.Column).Cut
            wsO.Columns(i + 1 - er).Insert xlShiftToRight
        Else
            er = er + 1
        End If
    Next i
End Sub

Remarques sur le code :

  • Déclaration de toutes les variables, et en-tête de procédure...
  • 2 variables Worksheet pour les deux feuilles : faciliter l'écriture en qualifiant les plages (et supprimant corrélativement les Select).
  • Une variable (type Variant) pour y lister dans l'ordre les libellés cherchés successivement (en utilisant Split...)
  • Boucle de 0 (indice mini) à l'indice max du tableau des libellés cherchés.

- Affectation searchrange (inchangée)...

NB- Je ne vois pas l'utilité du "A400", les libellés étant en ligne 1, et ensuite tu coupes la colonne entière...

Je l'ai laissée car si le nombre de lignes est commun sur Inscrits et Origine (ce qui n'est pas précisé), on pourrait ne couper et insérer que la partie utile de la colonne... On définit la colonne dans searchrange (ce qui la délimitera) et on insère sur une plage équivalente de 400 lignes...

- Quand on utilise Find, il est toujours souhaitable de vérifier que la recherche est fructueuse...

On peut ainsi poursuivre la procédure si elle ne l'était pas. Mais dans ce cas on provoquerait un décalage dû à la non insertion de colonne. Donc pour l'éviter, dans le cas d'une erreur éventuelle, on incrémente une variable (variable qui indique donc le nombre de colonnes éventuellement manquantes) que l'on déduira à l'insertion pour que celle-ci se fasse sur la bonne colonne. Si tout se passe sans erreur, la valeur de cette variable restera à 0.

- L'insertion se fait sur la colonne i+1 (i=0 pour le premier libellé...) et comme vu ci-dessus on diminue ce numéro de colonne de la variable er au cas où une insertion ait été loupée (ex.: on insère la 1re colonne trouvé en colonne A, on a une erreur sur la 2e qui n'est pas insérée, la variable er prend la valeur 1, la 3e aurait été insérée en C (sans correctif), laissant en B une colonne inadéquate, en faisant jouer er on l'insère en B : il manquera une colonne entre A et B mais on n'aura pas de fausse colonne à déplacer, on rétablira donc plus vite la situation ensuite).

Cordialement.

Bonjour MFerrand.

Réponse méga rapide et solide comme d'habitude, merci. Je vais étudier ça en détail.

J'ai une question comme ça à froid, tu écris

searchitems = Split("Numéro;Nom;Prénom;Ville;Adresse;Autre1;Autre2", ";")

", ";") à la fin sert à quoi en fait vu qu'il ne faut pas écrire "Numéro";"Nom"; etc etc

edit : j'ai intégré le code au mien. j'ai mis ceci :

searchitems = Split("Numéro;Nom;Prénom;Sexe;Date de Naissance;Ville de Naissance;Département de naissance;Série Diplôme;Oral de Français (épreuve anticipée);Ecrit de Français (épreuve anticipée);Physique Chimie Trimestre 1;Physique Chimie Trimestre 2;Physique Chimie Trimestre 3;Sciences de la Vie et de la Terre Trimestre 1;Sciences de la Vie et de la Terre Trimestre 2;Sciences de la Vie et de la Terre Trimestre 3;Autre2", ";")
    

N'ayant pas eu ta réponse j'ai préféré laisser Autre2", ";") au cas où.

La boucle marche bien mais se stoppe à "Ecrit de Français (épreuve anticipée)", le Physique Chimie Trimestre 1 n'est pas pris en compte et la macro se stoppe donc

Merci

La syntaxe de Split :

XXX = Split("chaîne", "séparateur")

La chaîne se met entre guillemets, évidemment, mais il n'y a qu'une seule chaîne, donc un guillemet avant et un après.

Si tu mets chaque terme entre guillemets, tu utilises Array pour obtenir un tableau. Split t'évite tous les guillemets intermédiaires.

Le séparateur par défaut est l'espace, dans ce cas tu peux l'omettre. Mais si tes libellés peuvent contenir des espaces, il convient de choisir un autre séparateur qui ne figurera pas dans la chaîne en tant que caractère texte. Le ; est en général adéquat pour séparer des libellés d'en-têtes...

Mais sache que le séparateur n'est pas limité à un seul caractère, tu peux en utiliser plusieurs, tu peux définir des mots, voire des expressions entières comme séparateur, ce qui donne un champ d'utilisation de Split qui va au delà de la simple constitution de tableau (combinée avec Join qui fait l'opération inverse : convertir un tableau en chaîne en introduisant un séparateur entre chaque élément, elle permet aussi de nombreuses opérations sur les chaînes).

Cordialement.

NB- Tu n'es pas obligé de citer le post précédent à chaque fois !

Désolé pour la citation, réflexe de pas mal de forums ou les gens changent ce qu'ils ont écrit et te font passer pour un con qui ne sait pas lire.

J'avais édit pour ne pas double post avant ta réponse je ne sais pas si tu as vu

j'ai intégré le code au mien. j'ai mis ceci :

searchitems = Split("Numéro;Nom;Prénom;Sexe;Date de Naissance;Ville de Naissance;Département de naissance;Série Diplôme;Oral de Français (épreuve anticipée);Ecrit de Français (épreuve anticipée);Physique Chimie Trimestre 1;Physique Chimie Trimestre 2;Physique Chimie Trimestre 3;Sciences de la Vie et de la Terre Trimestre 1;Sciences de la Vie et de la Terre Trimestre 2;Sciences de la Vie et de la Terre Trimestre 3;Autre2", ";")
    

N'ayant pas eu ta réponse j'ai préféré laisser Autre2", ";") au cas où.

La boucle marche bien mais se stoppe à "Ecrit de Français (épreuve anticipée)", le Physique Chimie Trimestre 1 n'est pas pris en compte et la macro se stoppe donc


Double post, au moins je suis sûr que ça sera lu.

J'ai compris pourquoi ça ne fonctionne pas. Entre le français et la physique j'ai 2 colonnes. Vu qu'il faut "sauter" ces colonnes pour les récupérer la macro se stoppe.

Ce que je veux c'est repérer les colonnes par leur en-tête et les mettre en ordre, mais elles sont mélangées. Exemple :

mon fichier :

A V E R C B Y R D....

Ce que je veux que ça fasse :

A B D C E F G H I J ...

Il faut que tu listes tes libellés complets, tels qu'ils figurent dans ton en-tête !

Et faire éventuellement attention aux espaces parasites...

Si les libellés sont conformes pas de raison que cela ne marche pas en principe.

Ah ben je ne vois pas alors

Voici un fichier épuré (j'ai supprimé toutes les données sauf 2 lignes test)

Macros à exécuter :

Test

puis Tri

c'est dans tri que j'ai inséré ton code, comme ça je valide par étapes mes macros.

Une fois Tri effectué on vois qu'il y a un soucis... je ne sais pas lequel si tu me dis que ça devrait marcher.

Il manque la feuille Origine ?

Ta macro d'origine présupposait une feuille Origine ayant déjà un contenu, sinon quelle utilité ?

Pour faire un reclassement de colonnes dans la même feuille, tu le fais dans la feuille.

Si tu listes des libellés n'existant pas, ce n'est pas sérieux, commence donc par les vérifier un par un !

Et si tu ne respectes pas la casse, prend la précaution de de rajouter dans Find : , MatchCase:= False

Exécute la macro Test en premier tu vas voir elle va apparaître ne fais pas que lire. La macro TRI arrive une fois la "test" exécutée

Sur la feuille inscrit il y a des données (plein en fait) que je ne souhaites par garder, changer de place etc. ça me parait compliqué de changer d'ordre des colonnes quand la destination est vaste d'ou mon projet de couper/coller dans une nouvelle feuille pour nettoyer

edit : Je mettrais les 2 macros bout à bout quand je serais sur que chaque partie fonctionne

Mon objectif : le rectorat me file un fichier dégueulasse avec des colonnes qui vont de A à CE, et j'ai juste a balancer la macro pour faire les tris et présentations que je veux.

J'ai déjà un fichier comme ça mais se réfère au nom des colonnes. Si l'an prochain un clampin décide de changer l'ordre ça fait tout foirer d'où la création de cette nouvelle macro.

OK tu crées une feuille Origine dans ta macro que je n'avais pas lu (j'ai fixé une limite de saturation à la lecture de code enregistré, ou non indenté, ou qui ne respecte pas des règle élémentaires de programmation... et passé la limite, je ne le lis systématiquement plus ! )

Si cette feuille Origine est créée pour la circonstance, l'insertion ne se justifie pas !

Cela ne t'empêche pas de dresser une liste des libellés de colonne qui soient conformes aux libellés de ta feuille Inscrits... et je ne vais sûrement pas le faire à ta place !

Mais tu devrais savoir que s'agissant de ta première macro, je ne vais pas aimer :

  • les fragments de code enregistrés (non réécrits entièrement)
  • le moindre Select (ou apparenté) non justifié (et ils ne le sont pas dans 99,9% des cas !)
  • des variables non déclarées, ou non déclarées en début de procédure !
  • ton indentation quelque peu fantaisiste (mais c'est mieux que si pas du tout ou complètement désordonné) !

Je ne garantis donc pas de la regarder... mais pour l'instant on a entamé la soirée chez moi et je ne me suis pas encore préoccupé de mon repas !

Cordialement.

Yes mon code est moche ce n'est pas mon premier mais j'ai appris sur le tas sans tuto et généralement dans l'urgence du boulot (j'en ai 2 donc mon temps libre n'est pas à la lecture de cours VBA mais a la préparation d'un examen en candidat libre)

Je vais essayer de l'améliorer pour que ce soit plus lisible XD

Passes une bonne soirée

J'ai bidouillé ça a l'air de marcher pour l'instant. Faut juste que je saisisse les 80 en-têtes qu'il me faut now. Je valide si je réussi le sujet

Une fois fait et opérationnel je vais tenter de nettoyer mon code pourras tu si tu as le temps le regarder voir ce qui peut être fait?

Merci pour l'aide tu gères comme d'habitude

Cdt

edit : j'ai fait la macro, testé, ça fonctionne, enregistre et ferme/ouvre le fichier, ça fonctionne plus -_-

Avec 80, il vaut mieux lister ça dans une feuille Excel, et les prélever là... Ce sera plus simple.

Sub CeQueTuVeuxFaire()
    Dim fd As Range, searchrange As Range, searchitems, i%, er%
    Dim wsI As Worksheet, wsO As Worksheet
    Set wsI = Sheets("Inscrits")
    Set wsO = Sheets("Origine")
    searchitems = Split("Numéro;Nom;Prénom;Ville;Adresse;Autre1;Autre2", ";")
    For i = 0 To UBound(searchitems)
        Set searchrange = wsI.Range("A1", wsI.Range("A400").End(xlToRight))
        Set fd = searchrange.Find(searchitems(i), , xlValues, xlWhole)
        If Not fd Is Nothing Then
            wsI.Columns(fd.Column).Cut
            wsO.Columns(i + 1 - er).Insert xlShiftToRight
        Else
            er = er + 1
        End If
    Next i
End Sub

Question : Ce code lit bien de gauche a droite normalement (xlToRight) mais si j'ai 2 en-têtes appelées "Physique Chimie T1" par exemple ça fonctionne, ça me prend la 1° colonne ou ça apparaît, puis ça passe à la suite?

Concrètement ça doit me prendre que la première fois où ça apparaît, continuer, puis prendre la 2° fois quand ça apparaît à nouveau dans split? si ce n'est pas le cas comment modifier?

Je ne vois qu'un xlToRight, repris de ton code initial. L'expression renvoie la dernière cellule occupée sur la ligne400 en partant de la colonne A (dès qu'elle trouve vide dans une colonne sur la ligne, elle s'arrête, et pour que ça fonctionne correctement, il faut que A400 et B400 soient occupées).

Cordialement.

MFerrand a écrit :

Je ne vois qu'un xlToRight, repris de ton code initial. L'expression renvoie la dernière cellule occupée sur la ligne400 en partant de la colonne A (dès qu'elle trouve vide dans une colonne sur la ligne, elle s'arrête, et pour que ça fonctionne correctement, il faut que A400 et B400 soient occupées).

Cordialement.

Ok ben je ne vois pas pourquoi ça marchait hier, j'ai enregistré fermé/rouvert ça marchait plus. J'en ai marre

Du coup je vais tout supprimer et recommencer du début.

Teste ce qui est renvoyé par l'expression, tu en auras le coeur net :

Sub Test()
    MsgBox ActiveSheet.Range("A400").End(xlToRight).Column
End Sub

Cela t'affichera le numéro de colonne pris en compte pour dimensionner searchrange.

Ensuite ta recherche porte sur toute la plage ainsi définie (400 lignes) mais je suppose qu'elle ne soit pouvoir trouvée que sur la ligne 1 (c'est celle qui est balayée en premier par défaut, sauf A1 qui étant la cellule de départ est testée en dernier).

autant mettre A1 partout du coup. Mais même avec A1 partout ça se stoppe après les notes de français

Tant que tu n'as pas testé ta ligne 400, tu ne sauras pas si cela est dû à des cellules vides sur cette ligne, ou à autre chose !

MFerrand a écrit :

Tant que tu n'as pas testé ta ligne 400, tu ne sauras pas si cela est dû à des cellules vides sur cette ligne, ou à autre chose !

J'ai testé ça me renvoie 82 (mon nombre de colonnes en gros)

Mais ça se stop a quelque colonnes donc c'est un fail

Rechercher des sujets similaires à "boucle remplacement"