TL;DR —
Range.Findes el Ctrl+F de Excel para código. No devuelve un número de fila ni una posición — devuelve unRangeque apunta a la celda coincidente, oNothingsi no hay coincidencia. Así que lo primerísimo que haces con el resultado es comprobarIs Nothing; sáltatelo y la primera ejecución sin coincidencia falla con «Object variable not set» (error 91). Dos argumentos son innegociables porque Find los recuerda de la última vez: fijaLookIn:=xlValuesyLookAt:=xlWholeen cada llamada, o tu macro hereda lo que sea que un usuario tecleó por última vez en el cuadro de diálogo de búsqueda.
' Busca "Widget" en la columna A e informa de su fila, con seguridad.
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 celda ES IGUAL A "Widget", no solo la contiene
If found Is Nothing Then
MsgBox "Not found"
Else
MsgBox "Found in row " & found.Row ' found es un Range - usa .Row, .Address, .Value
End If
Buscar en una hoja es la cosa más común que hace una macro, y Find es la herramienta correcta
para ello — es el propio motor de búsqueda optimizado de Excel, y le gana por mucho a un bucle
hecho a mano sobre cada celda con datos reales. Pero Find tiene más estado oculto que casi
cualquier otro método del modelo de objetos, y ese estado es la razón de que el mismo código dé
respuestas distintas en máquinas distintas. Esta guía se construye alrededor de dos hechos —
Find devuelve un objeto, y Find es pegajoso — y todo lo demás se deriva de ellos.
Lo que aprenderás
- El modelo mental —
Finddevuelve unRange(oNothing), no una posición - La comprobación que evita el fallo del error 91 — prueba
Is Nothingantes de tocar el resultado - La trampa de los argumentos pegajosos — por qué
LookInyLookAthay que fijarlos siempre, sin excepción xlWholefrente axlPart— la diferencia entre «igual a» y «contiene»- Recorrer con
FindNextpara obtener todas las coincidencias, sin un bucle infinito - Cuándo
Findgana a un bucle, y en qué se diferencia deInStr
El modelo mental: Find devuelve una celda, no un número
Si vienes de InStr, Find parece familiar pero no se comporta en nada como él. InStr busca
dentro de una cadena y devuelve un número — la posición del carácter de la coincidencia, o
0. Range.Find busca a lo largo de las celdas y devuelve un Range — un puntero vivo a
la celda en la que aterrizó, o el valor especial Nothing cuando nada coincidió.
Esa única diferencia lo condiciona todo. Como el resultado es un objeto, lo asignas con Set y
lees de él lo que necesitas: found.Row, found.Column, found.Address, found.Value. Y como
el «no hay coincidencia» se representa con Nothing y no con 0 o "", no puedes comprobarlo
con =. If found = Nothing ni siquiera compilará como esperas — Nothing se comprueba con la
palabra clave Is: If found Is Nothing.
Quédate con esa imagen — Find te da la celda o te da Nothing — y el fallo número uno que viene abajo resulta evidente antes de que ocurra.
La regla más importante: comprueba Is Nothing antes de tocar el resultado
Este es el error, y casi todo el mundo lo escribe una vez:
' INCORRECTO - da por hecho que Find siempre tiene exito.
Dim found As Range
Set found = ws.Columns("A").Find(What:="Widget", LookIn:=xlValues, LookAt:=xlWhole)
MsgBox found.Row ' error 91 en cuanto "Widget" no esta ahi
El código funciona perfectamente en las pruebas — porque tus datos de prueba contienen «Widget».
Publícalo, dale una hoja donde falte el valor, y Find devuelve Nothing. La siguiente línea le
pide a Nothing su .Row, y VBA lanza el error de ejecución 91, «Object variable or With
block variable not set». Es el error de Find más común que existe, y es del todo evitable:
' CORRECTO - primero ramifica segun Is Nothing.
Set found = ws.Columns("A").Find(What:="Widget", LookIn:=xlValues, LookAt:=xlWhole)
If found Is Nothing Then
' gestiona el "no encontrado" - mensaje, valor por defecto, salir
Else
' seguro usar found.Row, found.Value, etc.
End If
Cada Find va seguido de una comprobación Is Nothing. Trátalos como una sola unidad que
tecleas junta, igual que On Error y su controlador viajan juntos. No existe tal cosa como un
Find del que estés seguro de que va a coincidir — el sentido mismo de buscar es que no lo sabes.
La trampa que hace perder horas: Find recuerda sus últimos argumentos
Este es el comportamiento que hace que Find parezca embrujado. La mayoría de sus argumentos son
opcionales, y cuando omites uno, Find no usa un valor por defecto fijo — reutiliza el valor
de la última vez que Find se ejecutó, en cualquier parte de esta sesión de Excel. Eso incluye la
última búsqueda que un usuario tecleó a mano en el cuadro de diálogo de Ctrl+F.
Así que esta llamada de aspecto inocente:
Set found = ws.Cells.Find(What:="2026") ' LookIn? LookAt? MatchCase? ...heredados
puede coincidir con fórmulas en una ejecución y con valores en la siguiente, coincidir con la celda completa una vez y parcialmente la siguiente — según un estado que no puedes ver y que no fijaste. El síntoma es exasperante: «ayer funcionaba», «en mi máquina funciona», «a veces lo encuentra». La solución es disciplina — pasa los argumentos que deciden el resultado de forma explícita, siempre:
Set found = ws.Cells.Find( _
What:="2026", _
LookIn:=xlValues, _ ' xlValues (lo que ves) vs xlFormulas (la formula subyacente)
LookAt:=xlWhole, _ ' xlWhole (igual a) vs xlPart (contiene)
MatchCase:=False, _
SearchOrder:=xlByRows)
Mi regla: si un argumento puede cambiar en qué celda aterrizas — LookIn, LookAt, MatchCase —
lo nombras en cada llamada y nunca confías en el valor por defecto. Las tres pulsaciones de teclado
salen más baratas que el informe de errores.
xlWhole frente a xlPart: igual a frente a contiene
LookAt es el argumento que la gente equivoca con más frecuencia, porque ambos valores
«funcionan» y solo uno es correcto para la tarea. LookAt:=xlWhole coincide con una celda cuyo
contenido entero es igual a tu término de búsqueda. LookAt:=xlPart coincide con cualquier
celda que contenga el término en algún punto de su interior.
' La celda contiene el texto: Order 100 shipped
ws.Cells.Find(What:="100", LookAt:=xlWhole) ' SIN coincidencia - la celda no es exactamente "100"
ws.Cells.Find(What:="100", LookAt:=xlPart) ' coincide - "100" aparece dentro del texto
¿Buscas un ID, un código, una clave exacta? Quieres xlWhole, o coincidirás con «100» dentro de
«1002», «31007» y «Order 100». ¿Rastreas una palabra clave dentro de un texto más largo? Quieres
xlPart. Elegir el incorrecto es el clásico error de «¿por qué coincidió con esa celda?», y nunca
lanza un error — simplemente devuelve el Range equivocado.
Encontrar cada coincidencia: el bucle FindNext
Find devuelve una celda — la primera coincidencia después de la celda desde la que le dices
que empiece. Para actuar sobre cada aparición, recorres con FindNext, que continúa desde el
acierto anterior. El truco: FindNext da la vuelta al principio del rango cuando se pasa del
final, así que un bucle ingenuo se ejecuta para siempre. La solución es recordar la dirección de
la primera coincidencia y parar cuando vuelves a ella:
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 ' <-- recuerda donde empezamos
Do
found.Offset(0, 1).Value = "seen" ' haz algo con cada coincidencia
Set found = ws.Columns("A").FindNext(found)
Loop While Not found Is Nothing And found.Address <> firstAddress
End If
Olvidar capturar firstAddress es el error número uno de FindNext — el bucle da vueltas al
rango sin fin, reprocesando las mismas coincidencias. Una regla más que importa en silencio: no
elimines ni insertes filas dentro de un bucle FindNext. Cambiar la cuadrícula en mitad de la
búsqueda invalida el sentido de posición de Find; si necesitas eliminar coincidencias, recopila
primero sus direcciones y elimínalas después (mira VBA eliminar filas
para los patrones de bucle hacia atrás y Union).
Find y Replace en código
Range.Replace es el hermano de Find y comparte los mismos argumentos pegajosos, pero hace todo
el trabajo en una sola llamada — sin bucle, sin Is Nothing:
ws.Columns("A").Replace _
What:="N/A", Replacement:="0", _
LookAt:=xlWhole, MatchCase:=False
Como Replace actúa sobre todo el rango de una vez, es mucho más rápido que recorrer Find +
escribir cada celda — y devuelve True/False según si algo cambió, en lugar de un rango. Echa
mano de Replace cuando quieras cambiar coincidencias y de Find/FindNext cuando quieras
inspeccionarlas o navegar hasta ellas.
Find frente a InStr: búsqueda en la cuadrícula frente a búsqueda en cadenas
Suenan intercambiables y no lo son. Usa Find cuando lo que buscas es la hoja de cálculo
— quieres la celda, y quieres la búsqueda nativa y rápida de Excel. Usa InStr cuando lo que
buscas es una sola cadena que ya está en una variable — quieres una posición de carácter
dentro de ese texto. Un patrón habitual usa ambos: Find localiza la fila, y luego InStr extrae
una subcadena de un campo de esa fila. Si estás haciendo cirugía de texto dentro de cadenas, eso
es InStr y compañía, no Find.
Y el juicio que vale la pena decir con claridad: no escribas un bucle For Each cell In range
para encontrar un valor. Find es la búsqueda indexada propia de Excel; en una columna de
100.000 filas devuelve casi al instante mientras el bucle avanza penosamente por cada celda.
Montar la búsqueda a mano es más lento, más largo y más fácil de equivocar.
Cómo ayuda ExcelMaster
Find concentra una cantidad inusual de comportamiento oculto en un solo método: el resultado que
es objeto y no número, el resultado Nothing, los argumentos pegajosos, la elección entre
xlWhole/xlPart, el bucle que da la vuelta. Cada uno tiene un modo de fallo que produce
resultados incorrectos sin lanzar un error — exactamente el tipo de error que sobrevive a las
pruebas y aflora en producción.
ExcelMaster te deja describir la
búsqueda en su lugar. Di «encuentra cada fila donde el estado sea Cancelled y márcala» o «busca
este número de factura y salta a él», y escribe el Find con los argumentos fijados de forma
explícita, la protección Is Nothing en su sitio y un bucle FindNext como es debido cuando
necesitas todas las coincidencias — haciendo una copia de seguridad de la hoja antes de cambiar
nada. Te quedas con el libro y con el código; te ahorras la parte en la que un LookAt heredado
coincide en silencio con la celda equivocada.
Preguntas frecuentes
¿Por qué VBA Find da el error 91?
Porque Range.Find devuelve Nothing cuando no hay coincidencia, y el error 91 («Object variable
or With block variable not set») salta en el instante en que lees una propiedad como .Row de
Nothing. Comprueba siempre If found Is Nothing Then antes de usar el resultado. El fallo suele
aparecer solo cuando tus datos carecen del término de búsqueda, y por eso se cuela sin que las
pruebas lo detecten.
¿Qué devuelve VBA Find si no hay coincidencia?
Devuelve el valor especial Nothing, no 0 ni una cadena vacía. Debes comprobarlo con la palabra
clave Is — If found Is Nothing — porque Nothing no se puede comparar con =. Si hay
coincidencia, devuelve un Range que apunta a la celda encontrada.
¿Cuál es la diferencia entre LookAt xlWhole y xlPart en VBA Find?
xlWhole solo coincide con celdas cuyo contenido entero es igual al término de búsqueda; xlPart
coincide con cualquier celda que contenga el término en algún punto de su interior. Usa xlWhole
para claves exactas como IDs y códigos, y xlPart cuando rastreas una palabra clave dentro de un
texto más largo. Elegir el incorrecto devuelve la celda equivocada sin ningún error.
¿Cómo encuentro todas las celdas coincidentes en VBA, no solo la primera?
Usa Find para obtener la primera coincidencia, recuerda su .Address y luego recorre con
FindNext(found) hasta que la dirección vuelva a ser la primera: Loop While Not found Is Nothing And found.Address <> firstAddress. Capturar la primera dirección es esencial — sin ella el bucle
da vueltas al rango para siempre.
¿Debo usar VBA Find o un bucle para buscar en una hoja?
Usa Find. Es la búsqueda optimizada integrada de Excel y es mucho más rápida que un bucle
For Each sobre cada celda, sobre todo en rangos grandes. Un bucle manual es además más largo y
más propenso a errores. Recorre a mano solo cuando necesitas una lógica de coincidencia
personalizada que los argumentos de Find no pueden expresar.
Probado en
Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 08/08/2026.
Guías relacionadas: VBA AutoFilter · VBA Sort · VBA eliminar filas · VBA InStr · VBA Range
