Expresiones regulares en Python

Expresiones regulares en Python
Escrito 2 years ago

En anteriores entradas vimos una página web interesante para crear, buscar y probar expresiones regulares. En esta entrada vamos a ver como utilizar estas expresiones regulares en el lenguaje de programación Python.

Expresiones Regulares

Las expresiones regulares, son patrones que definen un conjunto de cadenas que puede ser finito o infinito. Por ejemplo, el conjunto de cadenas que formaría la expresión regular (bar|ar|mar)co, es barco, arco y marco. Es un conjunto finito. En cambio la expresión regular ab+c crea un conjunto infinito formado por: abc, abbc, abbbc, abbbbbc, .... Así infinitamente.

Este tema no trata de aprender expresiones regulares, sino de como usarlas en Python. Si quieres aprender expresiones regulares hay cientos de guías en la red. Incluida una página web muy interesante llamada regex101

Expresiones regulares en Python

Para utilizar expresiones regulares en Python es necesario importar el paquete re, que es encargado de gestionar todo el tema de las expresiones regulares. Lo siguiente es, declarar la expresión regular. Python nos ofrece 2 formas distintas de hacerlo:

Declarar expresion regular en Python
1
2
3
4
5
import re
# 1º forma
regex = r'(bar|ar|mar)co'
# 2º forma
regex = re.compile(r'(bar|ar|mar)co')

La 1º forma es más eficaz y ocupa menos espacio en memoria, porque solo es una simple cadena con el prefijo r, pero cada vez que se utiliza, esta crea las estructuras internas necesarias para su ejecución y una vez finalizada su tarea, destruye esas mismas estructuras. La 2º forma en cambio crea las estructuras desde el principio y no las destruyes hasta que la propia variable que contiene la expresión regular es destruida. Ocupa más espacio en memoria y necesita del paquete re de Python. ¿Cuál elegir? Pues depende del uso. Si solo vas utilizar una o 2 veces la misma expresión regular, la 1º forma es la mejor, porque ocupa menos espacio en memoria. Si la expresión regular se va a utilizar de manera repetida y en múltiples sitios. La 2º forma es la mejor, porque crea las estructuras al principio y no las borra cuando se utiliza la expresión regular.

Empezando con lo básico

Una vez visto lo básico, vamos a ver como utilizar las funciones para expresiones regulares de Python y que usos les podemos dar.

comprobar si cadena coincide con expresión regular
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import re

regex_format1 = re.compile(r'ab+c')
regex_format2 = r'ab+c'
text1 = 'abc'

if regex.search(text1):
print('La cadena está dentro del conjunto de la expresión regular')
else:
print('La cadena no está dentro del conjunto de la expresión regular')

# output La cadena está dentro del conjunto de la expresión regular.

text2 = 'test'
if re.search(regex_format2, text2):
print('La cadena está dentro del conjunto de la expresión regular')
else:
print('La cadena no está dentro del conjunto de la expresión regular')

# output La cadena no está dentro del conjunto de la expresión regular.

La función search() comprueba si una parte de un texto está dentro del conjunto de la expresión regular. Si es así devuelve un objeto llamado Match Object. Sino coincide devuelve None.

Match Object es un objeto que contiene información útil sobre el resultado de la expresión regular sobre una cadena.

Match Object
1
2
3
4
5
6
7
import re

regex = re.compile(r'[a-z]+')
text = '0122 test, test1'
mo = regex.search(text)
# group(0) devuelve la parte de la cadena que coincide con la expresión regular.
print(mo.group(0)) # output: test

match() vs search()

Existe cierta confusión con ambas funciones. Las 2 sirven para lo mismo, comprobar que una cadena coincide con una expresión regular. Pero hay una diferencia fundamental entra ambas. match() comprueba que la cadena completa coincida con la expresión regular. search() comprueba si una parte de la cadena coincide con la expresión regular.

match vs search
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import re


# Expresión regular que comprueba que la cadena es un número.
regex = re.compile(r'[0-9]+')
text1 = '01234'

if regex.search(text1):
print('Entra porque text1 coincide con la expresión regular.')

if regex.match(text1):
print('Entra porque text1 coincide con la expresión regular.')

text2 = 'test 01234'
if regex.search(text2):
print('Entra porque parte de text2 coincide con la expresión regular.')

if regex.match(text2):
pass # No entrará
else:
print('No entra porque text2 no coincide con la expresión regular.')

Substituir con expresiones regulares

Sin duda esta es la función más útil de las expresiones regulares. La de sustituir la parte de la cadena de texto que coincide con la expresión regular. Para ello utilizamos la función sub() del paquete re de Python.

sustituir los espacios en blanco por -
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
import re

# Expresión regular que busca todos los caracteres espacios.
regex = re.compile(r'\s+')
text = " test1 test2 test3\ntest4 \ntest5 "

#Reemplazar todo los espacios por el caracter -.
result = regex.sub('-', text)

# output: -test1-test2-test3-test4-test5-

La expresión regular busca todos los caracteres considerados espacios en blanco y los reemplaza por el caracter -. Bastante sencillo si dominas las expresiones regulares. Pero la gracia de sustituir con expresiones regulares, es que puedes utilizar una función para procesar el texto seleccionado por la expresión y devolver una salida de texto; aquí es donde se vuelven útiles las expresiones regulares.

usar funciones para reemplazar texto
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import re


all_numbers = ['cero', 'uno', 'dos', 'tres', 'cuatro, 'cinco', 'seis', 'siete', 'ocho', 'nueve']

def replace_func(mo):
"""
Función que procesará las coincidencias de la cadena y la expresión regular.
Devuelve los números escritos con letras. Además si el número es par las letras estarán en mayúsculas.
:param mo: es un Match Object con la información de la subcadena que coincide con la expresión regular.
"""
number = int(mo.group(0))
if number % 2 == 0:
# es par. Devolvemos el número en letras mayúsculas.
return all_numbers[number].upper()

# no es par. Devolvemos el número en letras.
return all_numbers[number]

regex = re.compile(r'[0-9]')
text = 'test 1 6 3 8 0'

# Añadimo el nombre de la función.
result = regex.sub(replace_func, text)

print(result)
# output test uno SEIS tres OCHO CERO

En el ejemplo usamos la función replace_func para que procese las coincidencias del texto y la expresión regular. La función recibe un objeto del tipo Match Object con información de la subcadena que va a ser reemplazada así como los grupos que forman parte de la expresión regular.

El ejemplo quizás no sea práctico, pero nos da idea del pequeño potencial que tiene las expresiones regulares en Python. Podemos reemplazar por unas u otras cadenas en función de lo que extraigamos de la expresión regular. También podremos guardar los resultados de las expresiones regulares en variables externas para poder utilizarlas posteriormente. Así por ejemplo podemos capturar las etiquetas html de un código. O guardar el dominio de direcciones e-mails.

Recoger el dominio de direcciones e-mails
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import re

# Expresión regular para detectar y capturar una dirección e-mail.
regex = re.compile(r'(?P<User>[a-zA-Z1-9\._]+)@(?P<Domain>[a-zA-Z1-9]+(?:\.[a-zA-Z1-9]+)+)')
domains = [] # Variable guardará todo los dominios de direcciones e-mails extraidos del texto.
def get_email_domain(mo):
# Extraemos el subgrupo Host que contiene el dominio del e-mail.
domains.append(mo.group('Host')) # Añadimos el dominio extraido a la lista.
return ''

text= """
Dirección: support@buhoprogramador.com.
Secretario: test@gmail.com.
Trabajador 1: worker1@test.com,
Trabjaador 2: workder2@test.com
invalid email: test@invalid_domain
"""
regex.sub(get_email_domains, text)
print(domains)
# output ['buhoprogramador.com', 'gmail.com', 'test.com', 'test.com']

Cuidado con las expresiones regulares.

En esta entrada hemos visto algunos ejemplos de como utilizar las expresiones regulares en Python. Pero las expresiones regulares tienen un problema, y es su consumo de memoria y su tiempo de ejecución. Por lo que es recomendable reservarlas para cuando sean necesarias de verdad y no usarlas en trivialidades que se pueden resolver por otros métodos.

En próximas entradas veremos más ejemplos de expresiones regulares en Python y algunas técnicas más.

Comentarios