Go: verificación de inclusión de subcadena en una cadena — guía completa

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Cómo verificar en Go si una cadena contiene una subcadena? De principiante a experto

\n\n

¿Alguna vez has escrito en Go y te has quedado paralizado ante una pregunta simple: «¿Esta cadena contiene la parte que necesito?» Si es así, no estás solo. En Stack Overflow, esta pregunta ha acumulado miles de visitas, y con razón. En Go, hay varias formas elegantes de resolver este problema, pero ¿cuál elegir? Aclaremos esto de una vez por todas.

\n\n

En este artículo, no solo te mostraremos la función strings.Contains. Te enseñaremos a pensar como un desarrollador de Go: elegir la herramienta óptima para cada situación, evitar trampas y escribir código que sea rápido y predecible.

\n\n

Contenido

\n\n\n

1. strings.Contains — tu primer amigo

\n\n

Empecemos con la forma más simple y popular. La función strings.Contains de la biblioteca estándar de Go es lo que necesitas en el 80% de los casos. Devuelve true si la cadena contiene la subcadena especificada y false en caso contrario.

\n\n

Así se ve en código real:

\n\n
package main\n\nimport (\n    "fmt"\n    "strings"\n)\n\nfunc main() {\n    str := "¡Hola, mundo Go!"\n    substr := "mundo"\n\n    if strings.Contains(str, substr) {\n        fmt.Println("La cadena contiene la subcadena:", substr)\n    } else {\n        fmt.Println("Subcadena no encontrada")\n    }\n}\n
\n\n

Salida:

\n
La cadena contiene la subcadena: mundo
\n\n

Simple, ¿verdad? La función distingue entre mayúsculas y minúsculas: strings.Contains("Go", "go") devolverá false. Si necesitas ignorar mayúsculas/minúsculas, tendrás que usar strings.ToLower o strings.EqualFold.

\n\n

Ejemplo ignorando mayúsculas/minúsculas

\n\n
str := "Golang is awesome"\nsubstr := "golang"\n\nif strings.Contains(strings.ToLower(str), strings.ToLower(substr)) {\n    fmt.Println("¡Encontrado (sin distinción de mayúsculas)!)\n}\n
\n\n

Cuándo usarlo: cuando necesitas una respuesta binaria simple: «sí» o «no». Sin detalles adicionales.

\n\n

2. strings.Index — cuando necesitas saber la posición

\n\n

A veces no basta con saber que la subcadena existe. Quieres entender dónde está exactamente. Por ejemplo, estás analizando un registro y quieres extraer una parte de la cadena después de un marcador específico. Aquí es donde strings.Index viene al rescate.

\n\n

Esta función devuelve el índice de la primera aparición de la subcadena (comenzando en 0) o -1 si la subcadena no se encuentra.

\n\n
str := "Error: archivo no encontrado en /var/log"\nsubstr := "archivo"\n\npos := strings.Index(str, substr)\nif pos != -1 {\n    fmt.Printf("Subcadena encontrada en la posición %d\\n", pos)\n    fmt.Printf("Contexto: %s\\n", str[pos:])\n} else {\n    fmt.Println("Subcadena no encontrada")\n}\n
\n\n

Salida:

\n
Subcadena encontrada en la posición 7\nContexto: archivo no encontrado en /var/log
\n\n

Hay otras variaciones:

\n
    \n
  • strings.LastIndex — busca la última aparición
  • \n
  • strings.IndexAny — busca la primera aparición de cualquier carácter de un conjunto
  • \n
  • strings.IndexRune — busca un carácter Unicode específico
  • \n
\n\n
// Ejemplo con LastIndex\nstr := "a-b-c-d"\nlastDash := strings.LastIndex(str, "-")\nfmt.Println("Último guion en la posición:", lastDash) // 5\n\n// Ejemplo con IndexAny\nstr2 := "hello world"\npos := strings.IndexAny(str2, "aeiou")\nfmt.Println("Primera vocal en la posición:", pos) // 1\n
\n\n

Cuándo usarlo: cuando necesitas la posición de la subcadena para extraer, reemplazar o analizar más a fondo.

\n\n

3. ContainsAny y ContainsRune — ajuste fino

\n\n

¿Qué pasa si no necesitas buscar una subcadena completa, sino cualquier carácter de un conjunto? Por ejemplo, verificar si una cadena contiene algún dígito o algún signo de puntuación. Aquí es donde brillan strings.ContainsAny y strings.ContainsRune.

\n\n

strings.ContainsAny devuelve true si la cadena contiene al menos uno de los caracteres Unicode especificados en el segundo argumento.

\n\n
package main\n\nimport (\n    "fmt"\n    "strings"\n)\n\nfunc main() {\n    texto := "¡Hola, mundo 2024!"\n\n    // ¿Contiene algún dígito?\n    if strings.ContainsAny(texto, "0123456789") {\n        fmt.Println("El texto contiene dígitos")\n    }\n\n    // ¿Contiene algún signo de puntuación?\n    if strings.ContainsAny(texto, ".,!?;:") {\n        fmt.Println("El texto contiene signos de puntuación")\n    }\n}\n
\n\n

Salida:

\n
El texto contiene dígitos\nEl texto contiene signos de puntuación
\n\n

strings.ContainsRune es aún más específico: verifica si la cadena contiene un rune (carácter Unicode) particular.

\n\n
texto := "Café"\n\nif strings.ContainsRune(texto, 'é') {\n    fmt.Println("El texto contiene el carácter 'é'")\n}\n
\n\n

Cuándo usarlos: cuando necesitas verificar la presencia de cualquier carácter de un conjunto, no una subcadena completa.

\n\n

4. Rendimiento: ¿qué elegir?

\n\n

Ahora que conoces todas las herramientas, surge la pregunta: ¿cuál es más rápida? Realicé pruebas simples con cadenas de diferentes longitudes y aquí están los resultados.

\n\n

Para la mayoría de los casos de uso cotidiano (cadenas de hasta unos pocos kilobytes), la diferencia entre strings.Contains y strings.Index es insignificante. Ambas funciones están altamente optimizadas y utilizan el algoritmo de búsqueda de cadenas de Rabin-Karp internamente.

\n\n

Sin embargo, hay matices:

\n
    \n
  • strings.Contains es ligeramente más rápido cuando solo necesitas un resultado booleano, porque no calcula la posición exacta.
  • \n
  • strings.Index es la mejor opción si de todos modos necesitas la posición; no tiene sentido llamar a Contains y luego a Index.
  • \n
  • ContainsAny puede ser más lento en cadenas largas si el conjunto de caracteres es grande, pero para la mayoría de los casos es suficiente.
  • \n
\n\n

Regla general: no te preocupes por la optimización prematura. Elige la función que exprese mejor tu intención. El compilador y el recolector de basura de Go harán el resto.

\n\n

5. Casos extremos y trampas

\n\n

Incluso las funciones simples tienen sus peculiaridades. Aquí hay algunos casos que debes tener en cuenta:

\n\n

Cadena vacía

\n

Una cadena vacía siempre está contenida en cualquier cadena:

\n\n
fmt.Println(strings.Contains("abc", "")) // true\nfmt.Println(strings.Index("abc", ""))    // 0 (principio de la cadena)
\n\n

Esto puede ser inesperado si no lo sabes. Siempre verifica si la subcadena no está vacía si eso es importante para tu lógica.

\n\n

Unicode y multibyte

\n

Go maneja UTF-8 de forma nativa, pero recuerda que strings.Index devuelve el índice en bytes, no en caracteres (runas). Si trabajas con texto que contiene caracteres multibyte (por ejemplo, emojis o caracteres cirílicos), usa utf8.RuneCountInString para contar runas.

\n\n
str := "Привет, мир!"\npos := strings.Index(str, "мир")\nfmt.Println("Índice en bytes:", pos) // 8 (no 8 caracteres)\n\n// Para obtener el índice en runas:\nimport "unicode/utf8"\nrunas := utf8.RuneCountInString(str[:pos])\nfmt.Println("Índice en runas:", runas) // 8
\n\n

Distinción de mayúsculas y minúsculas

\n

Ya lo mencionamos, pero vale la pena repetirlo: todas las funciones estándar distinguen entre mayúsculas y minúsculas. Para búsquedas sin distinción, usa strings.ToLower o strings.EqualFold.

\n\n

6. Resumen: qué recordar

\n\n

Hemos recorrido un largo camino. Aquí están los puntos clave:

\n\n
    \n
  • strings.Contains — tu opción predeterminada para verificar la presencia de una subcadena. Simple y clara.
  • \n
  • strings.Index — cuando necesitas la posición de la subcadena. Útil para extraer o reemplazar partes de una cadena.
  • \n
  • strings.ContainsAny y ContainsRune — para verificar la presencia de cualquier carácter de un conjunto.
  • \n
  • No olvides los casos extremos: cadena vacía, Unicode y distinción de mayúsculas/minúsculas.
  • \n
  • Elige la función que exprese mejor tu intención, no la más rápida. La legibilidad del código es más importante que la microoptimización.
  • \n
\n\n

Ahora estás listo para manejar cualquier tarea de búsqueda de subcadenas en Go. ¡Escribe código con confianza!

Blogs

Book Recommendations