Las expresiones regulares (regex) constituyen un lenguaje especializado diseñado para la búsqueda y manipulación de patrones de texto. En el ecosistema de Python, esta funcionalidad se integra a través del módulo nativo re. Estas herramientas resultan indispensables para validar formatos como direcciones de correo electrónico, analizar registros del sistema, extraer información específica o transformar cadenas de texto complejas. Internamente, los patrones regex se traducen a código de bytes que un motor de evaluación escrito en C procesa con alta eficiencia.
Fundamentos de Coincidencia de Caracteres
Los caracteres alfanuméricos estándar coinciden literalmente consigo mismos. Por ejemplo, el patrón python encontrará exactamente la subcadena "python". Sin embargo, la verdadera potencia radica en los metacaracteres, los cuales otorgan capacidades lógicas y de cuantificación.
Conjuntos de Caracteres: [ ] y [^ ]
Los corchetes permiten definir un grupo de opciones válidas para una posición específica. Si se antepone el símbolo ^ dentro del conjunto, la lógica se invierte para coincidir con cualquier carácter que no esté listado.
import re
palabras = "gato, gota, gito, gXto, g1to"
patron_vocales = r'g[aeiou]to'
patron_no_vocales = r'g[^aeiou]to'
print(re.findall(patron_vocales, palabras))
# Resultado: ['gato', 'gota', 'gito']
print(re.findall(patron_no_vocales, palabras))
# Resultado: ['gXto', 'g1to']
Anclajes de Posición: ^ y $
El símbolo ^ obliga a que la coincidencia ocurra estrictamente al inicio de la cadena, minetras que $ restringe el patrón al final de la misma.
frase = "python es genial, aprende python"
buscar_inicio = r'^python'
buscar_fin = r'python$'
print(re.findall(buscar_inicio, frase))
# Resultado: ['python']
print(re.findall(buscar_fin, frase))
# Resultado: ['python']
Secuencias de Escape y Clases Predefinidas: \
La barra invertida anula el significado especial de los metacaracteres y también introduce atajos para conjuntos comunes:
\dy\D: Dígitos numéricos y no numéricos, respectivamente.\sy\S: Espacios en blanco (tabulaciones, saltos de línea) y caracteres visibles.\wy\W: Caracteres alfanuméricos (incluyendo guion bajo) y símbolos especiales.
Cuantificadores de Repetición
Para especificar la frecuencia con la que un elemento debe aparecer, se utilizan cuantificadores específicos.
Repeticiones Exactas y Rangos: {m,n}
Permite establecer límites inferiores (m) y superiores (n) de ocurrencias. Omitir m asume cero, y omitir n asume infinitas repeticiones.
codigo_postal = "28012"
patron_exacto = r'^\d{5}$' # Exactamente 5 dígitos
patron_rango = r'^\d{3,5}$' # Entre 3 y 5 dígitos
print(bool(re.match(patron_exacto, codigo_postal))) # True
print(bool(re.match(patron_rango, codigo_postal))) # True
Cero o Más: *
El asterisco indica que el carácter precedente puede repetirse indefinidamente o no aparecer en absoluto.
patron_cero_o_mas = r'ab*c'
print(re.findall(patron_cero_o_mas, 'ac')) # ['ac'] (0 veces 'b')
print(re.findall(patron_cero_o_mas, 'abbc')) # ['abbc'] (2 veces 'b')
Una o Más: +
A diferencia del asterisco, el signo más exige que el elemento esté presente al menos una vez.
patron_una_o_mas = r'ab+c'
print(re.findall(patron_una_o_mas, 'ac')) # [] (Falta 'b')
print(re.findall(patron_una_o_mas, 'abc')) # ['abc']
Carácter Opcional y Modo No Codicioso: ?
El signo de interrogación señala que el carácter previo es opcional. Adicionalmente, cuando se coloca después de otro cuantificador, altera el comportamiento del motor de búsqueda de codicioso (greedy) a no codicioso (lazy).
formato_fecha = "12-05-2023 y 7-5-2023"
patron_guion_opcional = r'\d{1,2}-?\d{1,2}-?\d{4}'
print(re.findall(patron_guion_opcional, formato_fecha))
# Resultado: ['12-05-2023', '7-5-2023']
texto_html = "<p>contenido</p><p>mas texto</p>"
patron_codicioso = r'<p>.*</p>'
patron_no_codicioso = r'<p>.*?</p>'
print(re.findall(patron_codicioso, texto_html))
# Resultado: ['<p>contenido</p><p>mas texto</p>']
print(re.findall(patron_no_codicioso, texto_html))
# Resultado: ['<p>contenido</p>', '<p>mas texto</p>']