Excel - Macro - Recherche par mots clés pb. [Résolu/Fermé]

Signaler
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010
-
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010
-
Bonjour,
Voilà mon problème,

Tout d'abord je ne suis pas, encore, tres calé en VBA mais j'essaie d'apprendre.

Je dois en ce moment créer une macro dont le but serait le suivant (je vais donner un exemple au hasard):

J'ai un tableau avec une base de données de mots clés (113 mots + un second critère aussi des mots clé, mais j'imagine que si je trouve la réponse pour un, le deuxième pourrait se faire par un "and" ou autre, donc je ne vais pas l'évoquer)), et pour chaque mot clé j'ai une famille de produit et d'autre informations.

A coté j'ai un autre tableau (qui devra être remplit par la macro) dans lequel à chaque fois il faudra coller les "codes" contenant donc un des mots clés, le but de la macro est d'aller chercher que pour chaque cellule des codes entrés nous avons un mot clé, et une fois trouvé rapatrier la famille article etc pour chaque code.

Par exemple :

Je rentre un code : "5698 - Eau - KHG"
Dans ma base de données j'ai un mot clé : "Eau", et je dois donc rapatrier sa famille produit : "Liquide" et d'autres données.

Etant un débutant j'aurais tendance de faire un vlookup...mais avec plus de 100 mots clés ce serait énorme et je suis sur qu'il existe une solution moins compliquée. En cherchant sur ce forum j'ai trouvé le début de macro :
"
For Each cel In Sheets(1).Range("a3:a17") ' pour l'exemple je me contente des codes entrés dans l'ensemble des cellules A3:A17
If InStr(cel.Value, Range("f3").Value) then ... ' "F3" étant le mot clé à chercher
"
Le problème c'est que je n'arrive pas à faire en sorte que la macro ne cherche pas un seul mot clé mais bien "chaque mot clé dans ma base de donnée", comme ça par exemple : InStr(cel.Value, Range("f3:f113").Value)
Mais cette formule ne marche pas :(

Je me demande s'il n'y a pas un code équivalent à "For each cel in ..." à mettre dans mon critère de recherche "InStr(...)".

J'ai essayé d'être le plus précis, mais je peux toujours donner d'autres précisions s'il le faut, ou d'expliquer mieux certains points.

En tout cas je remércie par avance toute personne qui voudra m'aider.

PS: je cale aussi pour la suite de "Then", même si pour l'instant ce n'est pas la priorité, mais je pense y arriver en utilisant le "do while" + compteur, pour au final avoir un résultat : que pour chaque cellule (de mes codes) la macro cherche le mot clé, rapporte la famille produit etc, et les mettes bien en face du code concerné.

16 réponses

Messages postés
14934
Date d'inscription
lundi 18 octobre 2004
Statut
Contributeur
Dernière intervention
24 juin 2020
4 245
bonjour

Tu es parti avec : "If InStr(cel.Value, Range("f3").Value) then ...

Tu pourrais faire :
for i = 3 to 113
If InStr(cel.Value, Range("f" & i).Value) then ...
next i
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Bonjour,

Merci pour votre réponse, elle a en partie résolu le problème mais...

Problème principal :

La macro cherche bien dans ma base de données des mots clés, mais elle cherche que sur la meme ligne (C'est à dire que si j'ai en "A1" : "Eau - 3025 - JNK", et que sur la meme ligne dans la base de donnée des mots clés, donc "F1", j'ai : "Eau" ; alors j'obtiens le bon résultat. Mais il suffit de décaler le mot clé "Eau" sur la cellule d'en bas, "F2", et je n'ai pas de résultat.).
En fait la macro ne balaye pas l'ensemble de la base des mots clés mais juste les cellules se trouvant sur la meme ligne.

J'en profite pour poster ma macro teste (donc je ne fait pas de repatriment des "familles produit" mais je mets juste un "ok" dans la cellule "famille produit", si la macro trouve le bon résultat). Peut-etre vous pourrez m'aider.


Macro :

Sub Famille_Produit()
Dim FamProd As Range
Dim LibArt As Range

Set LibArt = Range("a3") ' c'est donc la cellule avec le code produit (appelée Libellé Article).
Set FamProd = Range("b3") ' c'est la cellule qui va recevoir un "ok" si le code article contient un des mots clés.

Do Until LibArt.Offset(i) = "" 'juste pour dire de ne pas continuer la macro s'il n'y a plus de codes articles.

For Each cel In Sheets(1).Range("a3:a113")
For i = 3 To 113
If InStr(cel.Value, Range("f" & i).Value) Then
FamProd.Offset(i) = "ok"

End If
Next i
Next
Loop
End Sub


Rien qu'avec ça je recontre deja quelques petits soucis, du genre j'obtiens le bon résultat (enfin, comme je l'ai dit plus haut, par rapport aux mots clés en face seulement) mais il est décallé d'une cellule plus bas...le problème c'est que c'est la valeur de "B" qui influe sur ça, or, en la mettant à 1 ("B1") j'ai toujours une cellule de décallage (au lieu de 3)...

Enfin bref, le principal c'est de résoudre le problème du "balayage" des mots clés, le reste viendra avec qui sait? :)

Merci encore pour toute personne qui a une idée à me proposer.
Messages postés
14934
Date d'inscription
lundi 18 octobre 2004
Statut
Contributeur
Dernière intervention
24 juin 2020
4 245
bonjour

Si tu veux balayer autre chose que la colonne A, faudrait lui dire :
For Each cel In Sheets(1).Range("a3:F113")

Pour mettre le résultat en Range("b3") :
FamProd = "ok"

Si tu mets un offset, tu es forcément décalé et en plus avec une valeur qui n'a rien à voir.
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Bonjour,

En faisant un balayage sur A3:F113 j'obtiens des "ok" partout. Et meme apres avoir supprimé la partie : "do until", "loop", "offset", j'ai toujours ce décallage.
En fait je suis bete je vais poster une image du tableau peut etre ce sera plus facile à comprendre.

http://pix.nofrag.com/3/a/8/20def379a58af54caa90e170d0cb6.html
Merci encore!
Messages postés
14934
Date d'inscription
lundi 18 octobre 2004
Statut
Contributeur
Dernière intervention
24 juin 2020
4 245
bonjour

Ta macro corrigée car tu avais mélangé un peu les différentes façon de boucler.
Sub Famille_Produit()
Dim FamProd As Range
Dim LibArt As Range
Dim Ligne As Long
Dim i As Long

Set LibArt = Range("a3") ' c'est donc la cellule avec le code produit (appelée Libellé Article).
Set FamProd = Range("b3") ' c'est la cellule qui va recevoir un "ok" si le code article contient un des mots clés.
Ligne = 0
Do Until LibArt.Offset(Ligne, 0) = "" 'juste pour dire de ne pas continuer la macro s'il n'y a plus de codes articles.
    For i = 3 To 113
        If InStr(LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) Then
            FamProd.Offset(Ligne, 0) = Range("f" & i).Offset(0, 1).Value
            Exit For
        End If
    Next i
    Ligne = Ligne + 1
Loop
End Sub

Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Merci "gbinforme", pour l'instant je ne peux pas tester (toute la semaine je pense non plus) mais des que je peux je vous tiens au courant!
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Merci beaucoup"gbinforme", en effet ça résout pas mal de choses (enfin ça résout complètement mon problème tel qu'il est posé :) ).

Mais comme je l’ai dit plus haut, je pose qu’une petite partie de ce que je veux faire réellement pour pouvoir résoudre les problèmes au fur et à mesure.

Maintenant j’utilise un double critère de recherche, c'est-à-dire que j’ai un mot clé principal et un mot clé secondaire (ça me permettra par la suite d’emporter d’autres « Familles » mais tout en son temps) . Donc dans la macro j’ai juste ajouté un « And » au « If » :


If InStr(LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) _
And InStr(LibArt.Offset(Ligne, 0).Value, Range("g" & i).Value) Then
….

Et j’ai un gros problème. Je croyais que la macro allait chercher le premier mot clé (ça, ça marche) et ensuite par rapport au premier, elle va chercher le deuxième tout simplement. Mais voilà, dans mon cas, et je ne sais pas pour quelle raison, la macro compte le nombre de caractères (espaces y compris) entre le premier mot clé et le deuxième et en fonction de ce nombre me donne un résultat nul (dans mes tests c’est en général lorsque je suis à plus de 6 caractères entres les deux mots clés) ou le bon (< à 6 caractères). Voilà un screenshot pour les exemples :
http://pix.nofrag.com/d/1/1/45d71c401cb9019bd822aebe23827.html

En réalité j’espère que je me suis pris la tête pour rien en faisant les tests pour savoir le nombre de caractères etc., et que peut être ça n’a rien à voir :)
Messages postés
14934
Date d'inscription
lundi 18 octobre 2004
Statut
Contributeur
Dernière intervention
24 juin 2020
4 245
bonjour

essaie plutôt avec la syntaxe complète
If InStr(1,LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) _
And InStr(LibArt.Offset(1,Ligne, 0).Value, Range("g" & i).Value) Then 
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Bonjour,

La formule complète prise telle qu'elle est donne un "Compile error : Wrong number of arguments or invalid property assignment".
Et meme en faisant :

If InStr(1,LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) _
And InStr(1,LibArt.Offset(Ligne, 0).Value, Range("g" & i).Value) Then

J'ai les meme résultats qu'avant.

Par contre en testant je viens de remarquer une chose qui a peut etre de l'importance... l'espace.
En fait j'ai fais un test : je rajoute à mon mot clé principal un espace et je fais "Entrée", ensuite je rajoute un espace à mon code article (donc j'ai 2 espaces apres le mot clé principal dans mon code article) et tout marche nicquel!! par contre en céant une nouvelle Famille + code sans ajouter d'espaces...rien, et si je rajoute à mon code article un espace, tout marche....


Je suis totalement perdu...pourquoi ces espaces ont tant d'importance?

alalalalala c'est d'un compliqué :)

Bon appétit :)
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Bonne nouvelle!!

En regardant l'aide d'excel sur "InStr" j'ai vu qu'il en existait une autre formule : "InStrB" (Extrait: "...InStrB returns the byte position"). Et ça marche!

Donc encore un problème résolu :)

Reste plus que le dernier, que je pensais réussir moi-meme (ça fait plusieurs heures que je testes) mais je coince.
Le problème est le suivant. Ma macro doit faire : D'abord aller chercher en fonction du mot clé principal la "famille produit" à repatrier dans la colonne "B". Ensuite (donc un autre "if") en fonction du mot clé principal ET le mot clé complémentaire repatrier "info supplémentaire n°1" dans la colonne "C" et "info supplémentaire n°2" dans la colonne "D".
J'en ai déduit donc la macro suivante :

......
For i = 3 To 113

If InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) Then
FamProd.Offset(Ligne, 0) = Range("f" & i).Offset(0, 2).Value

If InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) _
And InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("g" & i).Value) Then _
InfoSuppn°1.Offset(Ligne, 0) = Range("f" & i).Offset(0, 3).Value: _
InfoSuppn°2.Offset(Ligne, 0) = Range("f" & i).Offset(0, 4).Value

Exit For
End If

Next i
......

Sauf que mon résultat n'est pas complet. C'est à dire que les formules marchent, le premier "if" est parfait! Mais la deuxième partie me donnent certes des résultats mais pas pour tous mes "codes articles" (qui sont bons donc devraient avoir des résultats).

D'ailleurs la preuve que les formules "InStrB" marchent, c'est qu'en exécutant uniquement la deuxième partie :

.......
For i = 3 To 113
If InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) _
And InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("g" & i).Value) Then
InfoSuppn°1.Offset(Ligne, 0) = Range("f" & i).Offset(0, 3).Value: _
InfoSuppn°2.Offset(Ligne, 0) = Range("f" & i).Offset(0, 4).Value

Exit For
End If
Next i
.......


j'obtiens bien les résultats pour tous mes "codes articles".

Vous auriez une idée la dessus?

Merci d'avance.
Messages postés
14934
Date d'inscription
lundi 18 octobre 2004
Statut
Contributeur
Dernière intervention
24 juin 2020
4 245
bonjour

 For i = 3 To 113
If InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) _
And InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("g" & i).Value) Then
InfoSuppn°1.Offset(Ligne, 0) = Range("f" & i).Offset(0, 3).Value: _
InfoSuppn°2.Offset(Ligne, 0) = Range("g" & i).Offset(0, 4).Value

Exit For
End If
Next i 

Ne serait-ce pas ceci plutôt ?
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Bonjour,

En fait ça ne change rien en soit. J'avaisi mis :

InfoSuppn°1.Offset(Ligne, 0) = Range("f" & i).Offset(0, 3).Value: _
InfoSuppn°2.Offset(Ligne, 0) = Range("f" & i).Offset(0, 4).Value

Mais c'est pareil que:

InfoSuppn°1.Offset(Ligne, 0) = Range("f" & i).Offset(0, 3).Value: _
InfoSuppn°2.Offset(Ligne, 0) = Range("g" & i).Offset(0, 3).Value 'si j'ai bien compris la lettre designe la colonne et le 3 ici est le nombre de colonnes apres le "G". Du coup lorsque j'ai mis "g" et "4" je n'ai pas eu d'"infoSupp°2" puisque la 4ème colonne d'apres est vide.


Au final, si je veux je peux considérer le problème comme résolu, si ce que je cherchais était juste un résultat. Apres tout il me suffit de faire 2 macros (d'ailleurs en ce moment c'est le cas) une pour remplir "famille produit" et l'autre pour les "InfoSupp". Mais je cherche à comprendre pourquoi des macros qui marchent tres bien une par une, posent un problème une fois le code écrit dans une seule macro...
Messages postés
14934
Date d'inscription
lundi 18 octobre 2004
Statut
Contributeur
Dernière intervention
24 juin 2020
4 245
bonjour

En fait ce n'est pas les macros jumelées qui ne fonctionnent pas c'est la logique qui est erronnée :
Sub Famille_Produit()
Dim FamProd As Range
Dim LibArt As Range
Dim Ligne As Long
Dim i As Long

Set LibArt = Range("a3") ' c'est donc la cellule avec le code produit (appelée Libellé Article).
Set FamProd = Range("b3") ' c'est la cellule qui va recevoir un "ok" si le code article contient un des mots clés.
Ligne = 0
Do Until LibArt.Offset(Ligne, 0) = "" 'juste pour dire de ne pas continuer la macro s'il n'y a plus de codes articles.
    For i = 3 To 113
        If InStrB(1,LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) Then
            FamProd.Offset(Ligne, 0) = Range("f" & i).Offset(0, 1).Value
        End If
        If InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("g" & i).Value) Then
            InfoSuppn°2.Offset(Ligne, 0) = Range("g" & i).Offset(0, 1).Value
        End If
    Next i
    Ligne = Ligne + 1
Loop
End Sub

Comme ceci cela est plus logique car en ne prenant qu'une valeur de i cela donne forcément des résultats curieux si tes 2 recherches be sont pas sur la même ligne !
Il faut bien sûr régler les offset en fonction de ton fichier.
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Je suis surpris...
Enfin d'abord la bonne nouvelle : la macro marche enfin!! Je ne pourrais confirmer que demain mais à première vue j'obtiens les bons résultats!!!

mais voilà...

Tout d'abord pour le 2ème "end if" j'ai obtenu le message : "end if without block if"...et je peux vous garantir que j'ai TOUT regardé! évidemment j'avais mis un "if" exactement comme sur la formule...
Et en plus de ça le "exit for" il faut le supprimer aussi car sinon résultat encore étranges...
Bref je n'ai vraiment pas compris la logique lol.
Je poste le screenshot de la macro qui marche :

http://pix.nofrag.com/b/8/b/46ebce32bec66c4fbea4c985220bf.html

Autre chose, je ne pourrais confirmer que demain pour les résultats de la macro, mais si ce n'est pas trop demander pourriez vous me conseillez un bon site pour apprendre le VBA. Car en récrivant votre code j'ai compris pas mal de choses mais certaines je ne maitrise pas du tout :(


En tout cas un ENORME MERCI pour votre aide!!! :)

A demain.
Messages postés
14934
Date d'inscription
lundi 18 octobre 2004
Statut
Contributeur
Dernière intervention
24 juin 2020
4 245
bonjour

Si tu mets des soulignés en fin de ligne, tu n'as qu'une seule ligne pour VBA et donc pas de bloc de code et donc pas de fin if !

ceci devrait fonctionner en plus simple
Do Until LibArt.Offset(Ligne, 0) = "" 
    For i = 3 To 113
        If InStrB(1,LibArt.Offset(Ligne, 0).Value, Range("f" & i).Value) Then
            FamProd.Offset(Ligne, 0) = Range("f" & i).Offset(0, 1).Value
            If InStrB(1, LibArt.Offset(Ligne, 0).Value, Range("g" & i).Value) Then
                InfoSuppn°1.Offset(Ligne, 0) = Range("f" & i).Offset(0, 3).Value
                InfoSuppn°2.Offset(Ligne, 0) = Range("g" & i).Offset(0, 3).Value
            End If
        End If
    Next i
    Ligne = Ligne + 1
Loop


Tu as un site sur ton poste !
Quand tu ne connais pas une fonction, tu la sélectionnes et tu fais F1 tu auras plein d'infos !

Dans le sommaire tu as aussi toute la doc sur l'ensemble des objets et propriétés
Messages postés
25
Date d'inscription
lundi 5 juin 2006
Statut
Membre
Dernière intervention
11 novembre 2010

Merci énormément "gbinforme" tout marche à merveille, et en effet la touche "F1" est tres utile...quand on arrive à comprendre l'explication :)

Désolé de pas avoir répondu avant :(

Merci encore,
Bonne continuation.