¡Domina las Expresiones Regulares con el Módulo re de Python! Guía Completa de Búsqueda y Reemplazo de Cadenas
Para ejecutar Python desde el símbolo del sistema o PowerShell en tu PC, necesitas descargar e instalar Python.
Si aún no lo has hecho, consulta el artículo Instalación de Python y configuración del entorno de desarrollo para instalar Python.
Cuando creas sitios web o procesas datos, a menudo te encuentras con situaciones como "¡quiero extraer solo cadenas con un patrón específico de este texto!" o "¡quiero formatear en lote datos con formatos inconsistentes!". Ahí es cuando las "expresiones regulares" demuestran su increíble poder. ¿Parece difícil? ¡Para nada! Con el módulo `re` de Python, ¡incluso los principiantes pueden convertirse en maestros de la manipulación de cadenas de forma sorprendentemente fácil!
En este artículo, explicaremos desde lo básico hasta las aplicaciones de las expresiones regulares usando el módulo `re` de Python de una manera súper fácil de entender, con muchísimos ejemplos de código listos para copiar y pegar. Primero, intenta ejecutar el código para experimentar ese momento de "¡Ah, así es como se usa!". ¡Vamos a sumergirnos juntos en el mundo de las expresiones regulares!
Para empezar, ¿qué son las expresiones regulares y el módulo re?
Una expresión regular es, en pocas palabras, "una cadena de caracteres especial que describe un patrón de búsqueda". Es como un lenguaje común para buscar y reemplazar cadenas con condiciones ambiguas, como "una secuencia de tres números" o "algo con formato de dirección de correo electrónico".
Y la funcionalidad estándar (biblioteca) para manejar esas expresiones regulares en Python es el módulo `re`. Simplemente importando el módulo `re`, puedes realizar procesamientos complejos de cadenas con solo unas pocas líneas de código.
¡Primero lo Básico! Cuatro Funciones para "Buscar" Cadenas
El módulo `re` tiene varias funciones para buscar cadenas, pero primero dominemos las cuatro más utilizadas. Estas funciones toman como argumentos un "patrón de expresión regular" y una "cadena de destino para la búsqueda".
1. `re.search()` - Devuelve la primera coincidencia encontrada
`re.search()` examina toda la cadena y devuelve información sobre la primera parte que coincide con el patrón. Devuelve `None` si no encuentra ninguna coincidencia. Es la función de búsqueda más común y fácil de usar.
Por ejemplo, intentemos buscar la palabra "Python" en una frase.
<?php
import re
text = "Hello, this is a pen. I love Python programming!"
pattern = "Python"
# Buscar el patrón dentro de la cadena
match = re.search(pattern, text)
if match:
print(f"¡Encontrado!: '{match.group()}'")
print(f"Índice inicial: {match.start()}, Índice final: {match.end()}")
else:
print("No se encontró.")
# Resultado de la ejecución:
# ¡Encontrado!: 'Python'
# Índice inicial: 31, Índice final: 37
?>
2. `re.match()` - Comprueba si el "inicio" de la cadena coincide
`re.match()` es similar a `re.search()`, pero con una gran diferencia: solo comprueba si el patrón coincide desde el principio de la cadena. Los patrones que se encuentran en medio de la cadena son ignorados.
En la frase anterior, probemos ahora con `re.match()`. "Hello" coincidirá, pero "Python" no.
<?php
import re
text = "Hello, this is a pen. I love Python programming!"
# Patrón 1: "Hello" (al principio de la cadena)
match1 = re.match("Hello", text)
if match1:
print(f"Resultado de la búsqueda para 'Hello': ¡Coincide! -> {match1.group()}")
else:
print("Resultado de la búsqueda para 'Hello': No coincide.")
# Patrón 2: "Python" (en medio de la cadena)
match2 = re.match("Python", text)
if match2:
print(f"Resultado de la búsqueda para 'Python': ¡Coincide! -> {match2.group()}")
else:
print("Resultado de la búsqueda para 'Python': No coincide.")
# Resultado de la ejecución:
# Resultado de la búsqueda para 'Hello': ¡Coincide! -> Hello
# Resultado de la búsqueda para 'Python': No coincide.
?>
3. `re.findall()` - Devuelve "todas" las coincidencias en una lista
`re.findall()` encuentra todas las partes que coinciden con el patrón y las devuelve como una lista de cadenas. Es extremadamente útil cuando quieres extraer todos los números de una frase, por ejemplo.
Aquí, usemos el patrón de expresión regular `\d+`. Esto significa "una secuencia de uno o más dígitos".
<?php
import re
text = "El artículo A cuesta 100 por 1 pieza, y el artículo B cuesta 250 por 3 piezas. El número de pedido es 8801."
# \d+ es un patrón de regex que significa 'uno o más dígitos consecutivos'
pattern = r"\d+"
# Obtener todas las partes coincidentes como una lista
numbers = re.findall(pattern, text)
print(f"Lista de números encontrados: {numbers}")
# Resultado de la ejecución:
# Lista de números encontrados: ['1', '100', '3', '250', '8801']
?>
※ La `r` antes del patrón de expresión regular significa "cadena cruda" (raw string), y es un truco para evitar que la barra invertida `\` sea tratada como un carácter de escape. Se recomienda usarla al escribir expresiones regulares para prevenir errores innecesarios.
4. `re.finditer()` - Devuelve todas las coincidencias como un "iterador"
`re.finditer()` es similar a `re.findall()`, pero se diferencia en que devuelve los resultados como un "iterador" en lugar de una lista. Un iterador es adecuado para procesar elementos uno por uno, como en un bucle for.
Es útil cuando no solo quieres la cadena coincidente, sino también el objeto de coincidencia (que contiene información como la posición de inicio) que devolverían `search` o `match`.
<?php
import re
text = "Mi cumpleaños es el 31 de diciembre de 1995, y su cumpleaños es el 5 de mayo de 2003."
# Buscar números de 4 dígitos
pattern = r"\d{4}"
# Obtener las coincidencias como un iterador
matches = re.finditer(pattern, text)
print("Años encontrados:")
for m in matches:
print(f"- {m.group()} (posición: {m.start()}-{m.end()})")
# Resultado de la ejecución:
# Años encontrados:
# - 1995 (posición: 18-22)
# - 2003 (posición: 53-57)
?>
"Reemplazar" Cadenas a tu Antojo - re.sub()
Otra potente característica de las expresiones regulares es el "reemplazo". Con `re.sub()`, puedes reemplazar en bloque las partes que coinciden con un patrón por otra cadena.
Por ejemplo, reemplacemos los números de teléfono en un texto por la cadena "(oculto)" para proteger la privacidad. Usaremos la expresión regular `\d{2,4}-\d{2,4}-\d{4}`, que coincide con formatos de número de teléfono como 080-1234-5678.
<?php
import re
text = "Para consultas, contacte a nuestro personal de soporte Sato (080-1111-2222). O, contacte a nuestro representante de ventas Suzuki (03-3333-4444)."
# Regex para coincidir con números de teléfono
pattern = r"\d{2,4}-\d{2,4}-\d{4}"
replacement = "(oculto)"
# Reemplazar las partes que coinciden con el patrón
new_text = re.sub(pattern, replacement, text)
print(new_text)
# Resultado de la ejecución:
# Para consultas, contacte a nuestro personal de soporte Sato ((oculto)). O, contacte a nuestro representante de ventas Suzuki ((oculto)).
?>
Avanzado: Reemplazar usando grupos
El verdadero poder de `re.sub()` se desata cuando se combina con la función de "grupos" de las expresiones regulares. Al encerrar partes del patrón en `()`, puedes reutilizar esas partes (grupos) en la cadena de reemplazo.
Por ejemplo, cambiemos nombres que están en formato "Apellido-Nombre" a "Nombre Apellido".
<?php
import re
text = "Personajes: Tanjiro-Kamado, Zenitsu-Agatsuma, Inosuke-Hashibira"
# (\w+) es un grupo. El primero coincide con el apellido, el segundo con el nombre.
pattern = r"(\w+)-(\w+)"
# \2 se refiere al segundo grupo (nombre), \1 se refiere al primer grupo (apellido)
replacement = r"\2 \1"
new_text = re.sub(pattern, replacement, text)
print(new_text)
# Resultado de la ejecución:
# Personajes: Kamado Tanjiro, Agatsuma Zenitsu, Hashibira Inosuke
?>
【Pruébalo en Vivo】¡Construyamos un Verificador de Regex!
Usando el conocimiento que hemos adquirido, ¡construyamos un "Verificador de Regex" que te permita comprobar el comportamiento de las expresiones regulares en tiempo real en tu navegador!
Copia todo el código HTML a continuación, guárdalo en un archivo con un nombre como `verificador.html` y ábrelo en tu navegador. Introduce tu texto en el área de texto, el patrón que deseas probar (por ejemplo, `\d+` o `[A-Za-z]+`) en el campo de entrada de regex, y presiona el botón "Resaltar". Las partes coincidentes se resaltarán en azul claro. ¡Es un ejemplo perfecto para experimentar cómo "funciona" en vivo!
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verificador de Expresiones Regulares con Resaltado</title>
<style>
body {
background-color: #202124;
color: #e8eaed;
font-family: sans-serif;
line-height: 1.6;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
h1 {
color: #669df6;
border-bottom: 1px solid #5f6368;
padding-bottom: 10px;
}
textarea, input[type="text"] {
width: 100%;
padding: 10px;
margin-bottom: 10px;
background-color: #3c4043;
color: #e8eaed;
border: 1px solid #5f6368;
border-radius: 4px;
box-sizing: border-box; /* Incluir el padding en el cálculo del ancho */
}
button {
padding: 10px 20px;
background-color: #8ab4f8;
color: #202124;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
button:hover {
opacity: 0.9;
}
#result {
margin-top: 20px;
padding: 15px;
border: 1px solid #5f6368;
border-radius: 4px;
white-space: pre-wrap; /* Mostrar los saltos de línea tal cual */
word-wrap: break-word; /* Ajustar palabras largas */
}
.highlight {
background-color: #3367d6; /* Resaltar con azul claro */
color: #ffffff;
border-radius: 3px;
padding: 0 2px;
}
label {
display: block;
margin-bottom: 5px;
font-weight: bold;
}
</style>
</head>
<body>
<div class="container">
<h1>Verificador de Expresiones Regulares con Resaltado</h1>
<label for="text-input">Texto para probar:</label>
<textarea id="text-input" rows="8">Python 3.10 es la última versión. Mi email es sample-user@example.com. Por favor, llámame al 090-1234-5678. El evento es el 2025/07/26.</textarea>
<label for="regex-input">Patrón de Expresión Regular:</label>
<input type="text" id="regex-input" value="\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b">
<button onclick="highlightMatches()">Ejecutar Resaltado</button>
<label for="result" style="margin-top: 20px;">Resultado:</label>
<div id="result"></div>
</div>
<script>
function highlightMatches() {
const text = document.getElementById('text-input').value;
const regexPattern = document.getElementById('regex-input').value;
const resultDiv = document.getElementById('result');
if (!text || !regexPattern) {
resultDiv.textContent = 'Por favor, introduce texto y un patrón de expresión regular.';
return;
}
try {
// Añadir bandera g (búsqueda global) e i (no distinguir mayúsculas/minúsculas)
const regex = new RegExp(regexPattern, 'gi');
const highlightedText = text.replace(regex, (match) => {
return `<span class="highlight">${match}</span>`;
});
resultDiv.innerHTML = highlightedText;
} catch (e) {
resultDiv.textContent = 'Patrón de expresión regular no válido: ' + e.message;
}
}
// Ejecutar también en la carga inicial
document.addEventListener('DOMContentLoaded', highlightMatches);
</script>
</body>
</html>
¡Consejos y Trucos para Destacar!
Finalmente, cubramos algunas técnicas para usar las expresiones regulares de manera más efectiva y las trampas comunes en las que suelen caer los principiantes.
Coincidencia Voraz (Greedy) vs. No Voraz (Non-Greedy)
Por defecto, los cuantificadores de regex como `*` y `+` se comportan de manera "Voraz" (Greedy). Esto significa que intentan coincidir con la cadena más larga posible.
Por ejemplo, supongamos que quieres extraer solo el contenido entre `<p>` y `</p>`. ¿Qué sucede si usas el patrón `<.*>` en una cadena como `<p>primer párrafo</p><p>segundo párrafo</p>`?
<?php
import re
html = "<p>primer párrafo</p><p>segundo párrafo</p>"
# Coincidencia Voraz (Greedy)
greedy_match = re.search(r"<.*>", html)
print(f"Coincidencia voraz: {greedy_match.group()}")
# Coincidencia No Voraz (Non-Greedy): añade ? después de *
non_greedy_match = re.search(r"<.*?>", html)
print(f"Coincidencia no voraz: {non_greedy_match.group()}")
# Resultado de la ejecución:
# Coincidencia voraz: <p>primer párrafo</p><p>segundo párrafo</p>
# Coincidencia no voraz: <p>
?>
Con la coincidencia voraz, capturó todo desde el primer `<` hasta el último `>`. Por otro lado, `*?`, que tiene un `?` después del `*`, es "No Voraz", lo que significa que intenta coincidir con la cadena más corta posible. Esto permite que la coincidencia termine tan pronto como se encuentra el primer `>`. Esta diferencia es crucial al analizar HTML o XML.
Mejora el Rendimiento con `re.compile()`
Si usas el mismo patrón de expresión regular repetidamente en tu programa, se recomienda "compilar" el patrón de antemano usando `re.compile()`.
Esto le ahorra a Python el esfuerzo de analizar el patrón cada vez, mejorando la velocidad de procesamiento. El objeto de patrón compilado tiene métodos como `search()` y `findall()`.
<?php
import re
# Compilar el patrón de dirección de correo electrónico
email_pattern = re.compile(r"[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}")
# Buscar usando el objeto compilado
text1 = "El contacto es a@b.com."
match1 = email_pattern.search(text1)
if match1:
print(f"Encontrado en Text1: {match1.group()}")
text2 = "El soporte es support@example.co.jp."
match2 = email_pattern.search(text2)
if match2:
print(f"Encontrado en Text2: {match2.group()}")
# Resultado de la ejecución:
# Encontrado en Text1: a@b.com
# Encontrado en Text2: support@example.co.jp
?>
También tiene el beneficio de organizar tu código y hacerlo más legible.
Resumen
En este artículo, hemos introducido los conceptos básicos de las expresiones regulares usando el módulo `re` de Python. Puede parecer un poco complicado al principio, pero una vez que descubras su poder, no podrás imaginar el procesamiento de texto sin las expresiones regulares.
- `re.search()`: Encuentra la primera aparición de un patrón en una cadena.
- `re.match()`: Comprueba si el principio de una cadena coincide con un patrón.
- `re.findall()`: Obtiene todas las apariciones de un patrón como una lista.
- `re.sub()`: Reemplaza partes de una cadena que coinciden con un patrón.
Al combinar estos conceptos básicos y dominar los metacaracteres, tus habilidades de procesamiento de datos mejorarán drásticamente. ¡No dudes en copiar y pegar el código de este artículo y probar varios patrones para familiarizarte con las expresiones regulares!
Próximos Pasos
Ahora que puedes manejar datos de texto libremente con expresiones regulares, ¿por qué no pruebas con operaciones de archivos? Los archivos CSV, en particular, son un formato importante utilizado en muchas aplicaciones web y análisis de datos. Domina cómo leer y escribir archivos CSV usando el módulo `csv` de Python en el siguiente artículo.