🚀The world's best VBA AI has evolved. ExcelMaster is now an autonomous Agent.Read more →
Back to Blog

VBA Find dans Excel — rechercher dans les cellules correctement (Find renvoie une Range, pas une position)

|

VBA Find dans Excel — rechercher dans les cellules correctement (Find renvoie une Range, pas une position)

En brefRange.Find est le Ctrl+F d'Excel pour le code. Elle ne renvoie pas un numéro de ligne ni une position — elle renvoie une Range pointant vers la cellule correspondante, ou Nothing en l'absence de correspondance. La toute première chose à faire avec le résultat est donc de tester Is 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 : passez LookIn:=xlValues et LookAt:=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 — Find renvoie une Range (ou Nothing), pas une position
  • La vérification qui évite le plantage error-91 — testez Is Nothing avant de toucher au résultat
  • Le piège des arguments persistants — pourquoi LookIn et LookAt doivent être définis à chaque fois
  • xlWhole vs xlPart — la différence entre « égale » et « contient »
  • Boucler avec FindNext pour obtenir chaque correspondance, sans boucle infinie
  • Quand Find bat une boucle, et en quoi elle diffère de InStr

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é IsIf 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