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

VBA Find en Excel — buscar celdas de la forma correcta (devuelve un Range, no una posición)

|

VBA Find en Excel — buscar celdas de la forma correcta (devuelve un Range, no una posición)

TL;DRRange.Find es el Ctrl+F de Excel para código. No devuelve un número de fila ni una posición — devuelve un Range que apunta a la celda coincidente, o Nothing si no hay coincidencia. Así que lo primerísimo que haces con el resultado es comprobar Is 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: fija LookIn:=xlValues y LookAt:=xlWhole en 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 — Find devuelve un Range (o Nothing), no una posición
  • La comprobación que evita el fallo del error 91 — prueba Is Nothing antes de tocar el resultado
  • La trampa de los argumentos pegajosos — por qué LookIn y LookAt hay que fijarlos siempre, sin excepción
  • xlWhole frente a xlPart — la diferencia entre «igual a» y «contiene»
  • Recorrer con FindNext para obtener todas las coincidencias, sin un bucle infinito
  • Cuándo Find gana a un bucle, y en qué se diferencia de InStr

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