En bref —
Range.Findest le Ctrl+F d'Excel pour le code. Elle ne renvoie pas un numéro de ligne ni une position — elle renvoie uneRangepointant vers la cellule correspondante, ouNothingen l'absence de correspondance. La toute première chose à faire avec le résultat est donc de testerIs Nothing; sautez cette étape et la première exécution sans correspondance plante avec « Object variable not set » (error 91). Deux arguments ne sont pas négociables, car Find les mémorise d'une fois sur l'autre : passezLookIn:=xlValuesetLookAt:=xlWholeà chaque appel, sinon votre macro hérite de ce qu'un utilisateur a tapé en dernier dans la boîte de dialogue Find.
' Trouver "Widget" dans la colonne A et renvoyer sa ligne - sans risque.
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Data")
Dim found As Range
Set found = ws.Columns("A").Find( _
What:="Widget", _
LookIn:=xlValues, _
LookAt:=xlWhole) ' xlWhole = la cellule EGALE "Widget", pas seulement le contient
If found Is Nothing Then
MsgBox "Not found"
Else
MsgBox "Found in row " & found.Row ' found est une Range - utilisez .Row, .Address, .Value
End If
Fouiller une feuille est la chose la plus courante qu'une macro fasse, et Find est le bon
outil pour cela — c'est le moteur de recherche optimisé d'Excel lui-même, et il bat de très loin
une boucle écrite à la main sur chaque cellule, sur de vraies données. Mais Find traîne plus
d'état caché que presque toute autre méthode du modèle objet, et c'est cet état qui fait que le
même code donne des réponses différentes sur des machines différentes. Ce guide s'articule autour
de deux faits — Find renvoie un objet, et Find est persistant — et tout le reste en découle.
Ce que vous allez apprendre
- Le modèle mental —
Findrenvoie uneRange(ouNothing), pas une position - La vérification qui évite le plantage error-91 — testez
Is Nothingavant de toucher au résultat - Le piège des arguments persistants — pourquoi
LookInetLookAtdoivent être définis à chaque fois xlWholevsxlPart— la différence entre « égale » et « contient »- Boucler avec
FindNextpour obtenir chaque correspondance, sans boucle infinie - Quand
Findbat une boucle, et en quoi elle diffère deInStr
Le modèle mental : Find renvoie une cellule, pas un nombre
Si vous venez de InStr, Find semble familière et ne se comporte pourtant en rien comme elle.
InStr cherche à l'intérieur d'une chaîne et renvoie un nombre — la position du caractère
de la correspondance, ou 0. Range.Find cherche à travers les cellules et renvoie une
Range — un pointeur vivant vers la cellule où elle s'est arrêtée, ou la valeur spéciale
Nothing quand rien ne correspond.
Cette seule différence commande tout le reste. Comme le résultat est un objet, vous l'affectez
avec Set, et vous y lisez ce dont vous avez besoin : found.Row, found.Column,
found.Address, found.Value. Et comme l'« absence de correspondance » est représentée par
Nothing et non par 0 ou "", vous ne pouvez pas la tester avec =. If found = Nothing ne
compilera même pas comme vous l'attendez — Nothing se teste avec le mot-clé Is :
If found Is Nothing.
Gardez cette image en tête — Find vous donne la cellule ou vous donne Nothing — et le plantage numéro un ci-dessous devient évident avant même de survenir.
La règle la plus importante : testez Is Nothing avant de toucher au résultat
Voici le bug, et presque tout le monde l'écrit une fois :
' FAUX - suppose que Find reussit toujours.
Dim found As Range
Set found = ws.Columns("A").Find(What:="Widget", LookIn:=xlValues, LookAt:=xlWhole)
MsgBox found.Row ' error 91 des l'instant ou "Widget" est absent
Le code fonctionne parfaitement à l'essai — parce que vos données de test contiennent « Widget ».
Livrez-le, donnez-lui une feuille où la valeur est absente, et Find renvoie Nothing. La ligne
suivante demande son .Row à Nothing, et VBA déclenche une error 91 (« Object variable or
With block variable not set »). C'est l'erreur Find la plus courante qui soit, et elle est
entièrement évitable :
' CORRECT - aiguiller d'abord sur Is Nothing.
Set found = ws.Columns("A").Find(What:="Widget", LookIn:=xlValues, LookAt:=xlWhole)
If found Is Nothing Then
' gerer le "not found" - message, valeur par defaut, sortie
Else
' on peut utiliser found.Row, found.Value, etc. sans risque
End If
Chaque Find est suivi d'un test Is Nothing. Traitez les deux comme un bloc unique que
vous tapez ensemble, de la même façon que On Error et son gestionnaire vont de pair. Il
n'existe pas de Find dont vous êtes sûr qu'il trouvera — tout l'intérêt d'une recherche, c'est
que vous ne savez pas.
Le piège qui fait perdre des heures : Find mémorise ses derniers arguments
C'est le comportement qui donne à Find des allures de maison hantée. La plupart de ses
arguments sont facultatifs, et lorsque vous en omettez un, Find n'applique pas une valeur par
défaut fixe — il réutilise la valeur de la dernière exécution de Find, n'importe où dans cette
session Excel. Y compris la dernière recherche qu'un utilisateur a tapée à la main dans la boîte
de dialogue Ctrl+F.
Ainsi, cet appel d'apparence anodine :
Set found = ws.Cells.Find(What:="2026") ' LookIn? LookAt? MatchCase? ...herites de la fois precedente
peut correspondre aux formules une fois et aux valeurs la fois suivante, correspondre à la cellule entière une fois et partiellement la suivante — selon un état que vous ne voyez pas et n'avez pas défini. Le symptôme rend fou : « ça marchait hier », « ça marche sur ma machine », « il le trouve parfois ». Le remède, c'est la discipline — passez explicitement, à chaque fois, les arguments qui décident du résultat :
Set found = ws.Cells.Find( _
What:="2026", _
LookIn:=xlValues, _ ' xlValues (ce que vous voyez) vs xlFormulas (la formule sous-jacente)
LookAt:=xlWhole, _ ' xlWhole (egale) vs xlPart (contient)
MatchCase:=False, _
SearchOrder:=xlByRows)
Ma règle : si un argument peut changer la cellule sur laquelle vous atterrissez — LookIn,
LookAt, MatchCase — vous le nommez à chaque appel et ne vous fiez jamais à la valeur par
défaut. Les trois frappes de clavier coûtent moins cher que le rapport de bug.
xlWhole vs xlPart : égale contre contient
LookAt est l'argument que l'on se trompe le plus souvent, parce que les deux valeurs
« fonctionnent » et une seule convient à la tâche. LookAt:=xlWhole correspond à une cellule dont
le contenu entier égale votre terme de recherche. LookAt:=xlPart correspond à toute cellule
qui contient le terme quelque part.
' La cellule contient le texte : Order 100 shipped
ws.Cells.Find(What:="100", LookAt:=xlWhole) ' AUCUNE correspondance - la cellule n'est pas exactement "100"
ws.Cells.Find(What:="100", LookAt:=xlPart) ' correspond - "100" apparait dans le texte
Vous recherchez un ID, un code, une clé exacte ? Prenez xlWhole, sinon vous ferez correspondre
« 100 » à l'intérieur de « 1002 », « 31007 » et « Order 100 ». Vous balayez un mot-clé au sein
d'un texte plus long ? Prenez xlPart. Choisir le mauvais, c'est le grand classique du bug
« pourquoi a-t-il pris cette cellule ? », et il ne déclenche jamais d'erreur — il renvoie
simplement la mauvaise Range.
Trouver chaque correspondance : la boucle FindNext
Find renvoie une cellule — la première correspondance après la cellule d'où vous lui dites
de partir. Pour agir sur chaque occurrence, vous bouclez avec FindNext, qui reprend à partir
de la correspondance précédente. Le hic : FindNext revient au début de la plage lorsqu'il
dépasse la fin, si bien qu'une boucle naïve tourne à l'infini. Le correctif consiste à mémoriser
l'adresse de la première correspondance et à s'arrêter quand vous y revenez :
Dim found As Range, firstAddress As String
Set found = ws.Columns("A").Find(What:="Widget", LookIn:=xlValues, LookAt:=xlWhole)
If Not found Is Nothing Then
firstAddress = found.Address ' <-- memoriser notre point de depart
Do
found.Offset(0, 1).Value = "seen" ' faire quelque chose avec chaque correspondance
Set found = ws.Columns("A").FindNext(found)
Loop While Not found Is Nothing And found.Address <> firstAddress
End If
Oublier de capturer firstAddress est le bug numéro un de FindNext — la boucle fait
indéfiniment le tour de la plage, retraitant les mêmes correspondances. Une règle de plus qui
compte discrètement : ne supprimez ni n'insérez de lignes à l'intérieur d'une boucle
FindNext. Modifier la grille en pleine recherche fausse le repère de position de Find ; si
vous devez supprimer des correspondances, collectez d'abord leurs adresses et supprimez ensuite
(voir VBA Delete Rows pour les schémas de boucle à rebours et
d'Union).
Rechercher et remplacer dans le code
Range.Replace est le pendant de Find et partage les mêmes arguments persistants, mais il fait
tout le travail en un seul appel — pas de boucle, pas de Is Nothing :
ws.Columns("A").Replace _
What:="N/A", Replacement:="0", _
LookAt:=xlWhole, MatchCase:=False
Comme Replace agit sur toute la plage d'un coup, il est bien plus rapide que de boucler Find +
écrire chaque cellule — et il renvoie True/False selon qu'il y a eu ou non un changement,
plutôt qu'une plage. Recourez à Replace quand vous voulez modifier les correspondances, et à
Find/FindNext quand vous voulez les inspecter ou vous y déplacer.
Find vs InStr : recherche dans la grille contre recherche dans une chaîne
Elles paraissent interchangeables, elles ne le sont pas. Utilisez Find quand ce que vous
fouillez est la feuille de calcul — vous voulez la cellule, et vous voulez la recherche native
et rapide d'Excel. Utilisez InStr quand ce que vous fouillez est une chaîne unique déjà
stockée dans une variable — vous voulez une position de caractère à l'intérieur de ce texte. Un
schéma courant combine les deux : Find localise la ligne, puis InStr extrait une sous-chaîne
d'un champ de cette ligne. Si vous pratiquez de la chirurgie de texte à l'intérieur de chaînes,
c'est l'affaire d'InStr et compagnie, pas de
Find.
Et le jugement mérite d'être dit sans détour : n'écrivez pas de boucle For Each cell In range
pour trouver une valeur. Find est la recherche indexée propre à Excel ; sur une colonne de
100 000 lignes, elle renvoie presque instantanément là où la boucle passe péniblement chaque
cellule. Écrire la recherche à la main est plus lent, plus long, et plus facile à rater.
Comment ExcelMaster aide
Find concentre dans une seule méthode une quantité inhabituelle de comportements cachés : le
retour objet-et-non-nombre, le résultat Nothing, les arguments persistants, le choix
xlWhole/xlPart, la boucle qui reboucle. Chacun a un mode de défaillance qui produit de mauvais
résultats sans déclencher d'erreur — exactement le genre de bug qui survit aux tests et refait
surface en production.
ExcelMaster vous laisse plutôt
décrire la recherche. Dites « trouve chaque ligne dont le statut est Annulé et signale-la » ou
« recherche ce numéro de facture et saute jusqu'à lui », et il écrit le Find avec les arguments
épinglés explicitement, le garde-fou Is Nothing en place, et une vraie boucle FindNext quand
vous avez besoin de toutes les correspondances — en sauvegardant la feuille avant de rien changer.
Vous gardez le classeur et le code ; vous vous épargnez le moment où un LookAt hérité fait
discrètement correspondre la mauvaise cellule.
Questions fréquentes
Pourquoi Find en VBA déclenche-t-il une error 91 ?
Parce que Range.Find renvoie Nothing en l'absence de correspondance, et une error 91
(« Object variable or With block variable not set ») se déclenche à l'instant où vous lisez une
propriété comme .Row sur Nothing. Testez toujours If found Is Nothing Then avant d'utiliser
le résultat. Le plantage n'apparaît en général que lorsque vos données ne contiennent pas le terme
recherché, d'où le fait qu'il passe à travers les tests.
Que renvoie Find en VBA en l'absence de correspondance ?
Il renvoie la valeur spéciale Nothing, pas 0 ni une chaîne vide. Vous devez la tester avec le
mot-clé Is — If found Is Nothing — car Nothing ne peut pas se comparer avec =. En cas de
correspondance réussie, il renvoie une Range pointant vers la cellule trouvée.
Quelle est la différence entre LookAt xlWhole et xlPart dans Find en VBA ?
xlWhole ne correspond qu'aux cellules dont le contenu entier égale le terme recherché ; xlPart
correspond à toute cellule qui contient le terme quelque part. Utilisez xlWhole pour les clés
exactes comme les ID et les codes, et xlPart pour balayer un mot-clé au sein d'un texte plus
long. Choisir le mauvais renvoie la mauvaise cellule sans aucune erreur.
Comment trouver toutes les cellules correspondantes en VBA, pas seulement la première ?
Utilisez Find pour obtenir la première correspondance, mémorisez son .Address, puis bouclez
avec FindNext(found) jusqu'à ce que l'adresse revienne à la première :
Loop While Not found Is Nothing And found.Address <> firstAddress. Capturer la première adresse
est essentiel — sans cela, la boucle fait indéfiniment le tour de la plage.
Faut-il utiliser Find ou une boucle pour fouiller une feuille en VBA ?
Utilisez Find. C'est la recherche optimisée intégrée d'Excel, bien plus rapide qu'une boucle
For Each sur chaque cellule, surtout sur de grandes plages. Une boucle manuelle est aussi plus
longue et plus sujette aux erreurs. Ne bouclez que lorsqu'il vous faut une logique de
correspondance sur mesure que les arguments de Find ne peuvent pas exprimer.
Testé dans
Testé dans : Excel 365 (Windows 11), VBA 7.1 — dernière vérification le 08/08/2026.
Guides associés : VBA AutoFilter · VBA Sort · VBA Delete Rows · VBA InStr · VBA Range
