Expresiones regulares

← Fundamentos de Python ⌂ Home

Objetivos

Desarrollo

Una expresión regular (regex) es una cadena que contiene una combinación de caracteres normales y metacaracteres (caracteres no alfabéticos que poseen un significado). Los caracteres normales hacen "match" con ellos mismos y la combinación de metacaracteres representan cantidades, ubicacion, o tipos de los diferentes caracteres.

Las expresiones regulares nos sirven para encontrar una determinada combinación de caracteres dentro de una cadena de texto.

Python utiliza el módulo re para trabajar con expresiones regulares. El módulo re contiene funciones para buscar patrones dentro de una cadena search o comprobar si una cadena se ajusta a un determinado criterio descrito mediante un patrón match.

Métodos comunes

Para los siguientes ejemplos haremos uso del siguiente archivo.

Vamos a comenzar con un ejemplo sencillo:

import re

random_emails = open('random-emails.txt')
data = random_emails.read()
random_emails.close()

nombre1 = r'Maxy Chumley' # raw string
nombre2 = r'Olav Brevetor' # raw string

if re.match(nombre1, data):
    print("Encontró la coincidencia ", nombre1)

if re.match(nombre2, data):
    print("Encontró la coincidencia ", nombre2)

Como podemos observar al realizar la ejecución, unicamente imprime el contenido de el primer if, debido a que el match lo realiza desde el inicio de la cadena, intentemos cambiar el método del segundo if por search para que realice la busqueda del nombre.

import re

random_emails = open('random-emails.txt')
data = random_emails.read()
random_emails.close()

nombre1 = r'Maxy Chumley'
nombre2 = r'Olav Brevetor'

if re.match(nombre1, data):
    print("Encontró la coincidencia ", nombre1)

if re.search(nombre2, data):
    print("Encontró la coincidencia ", nombre2)

Metacaracteres

Caracteres especiales

re.match(r".ola", "hola")
re.match(r".ola", "fola")
re.match(r"python|jython|cython", "cython")
re.match(r"python|jython|cython", "jython")
re.match(r"(p|j|c)ython", "python")
re.match(r"niñ(o|a)s", "niños")
re.match(r"[pjc]ython", "cython")
re.match(r"cadena[0-9]","cadena1")

Nota: para utilizar estos caracteres, sin su función especial, dentro de un patrón, deben ser escapados con una antidiagonal.

re.match(r"...\.","abc.")

Y dentro de un conjunto no necesitan ser escapados.

 re.match(r"python[.,]","python,")
re.match(r"python[^0-9a-z]","python+")

Indicaría que nos interesan las cadenas que comiencen por “python” y tengan como último carácter algo que no sea ni una letra minúscula ni un número.

re.match(r"^http","http://google.com")
re.match(r"http$","//google.comhttp")

Secuencias especiales

Cuantificadores

Con ayuda de los metacaracteres podemos lograr lo siguiente:

import re

random_emails = open('random-emails.txt')
data = random_emails.read()
random_emails.close()

patron = r'\w+ \w+'

print(re.search(patron, data))

Imprime el primer nombre encontrado en la cadena, \w hace match con 1 o más carcteres, seguido de un espacio y otro \w+. Otro ejemplo para encontrar el primer teléfono ¿cómo sería?

import re

random_emails = open('random-emails.txt')
data = random_emails.read()
random_emails.close()

patron = r'\(\d{3}\) \d+'

print(re.search(patron, data))

¿Y para encontrar todos los teléfonos? Unicamente hacemos uso del método findall

import re

random_emails = open('random-emails.txt')
data = random_emails.read()
random_emails.close()

patron = r"\(\d{3}\)\s\d+"

print(re.findall(patron, data))

Conjuntos

Un ejemplo para poder encontrar los emails podría ser el siguiente:

import re

random_emails = open('random-emails.txt')
data = random_emails.read()
random_emails.close()

patron = r"[-\w\d+.]+@[-\w\d.]+"

print(re.findall(patron, data))

Grupos

El método group del módulo re nos permite acceder a diferentes "matchs" de alguna coincidencia. Por ejemplo:

import re

Avenida universidad no 3000
direccion = r"(Calle|Avenida) ([a-zA-Z ]+) (No|no|#) (\d+)"

cadena = input("Ingresa direccion: ")

ma = re.match(direccion, cadena)
if ma: 
    print(ma.group(0)) # Representa a toda la cadena que hizo match
    print(ma.group(1)) # Grupo de avenida o calle
    print(ma.group(2)) # Grupo de nombre de avenida o calle
    print(ma.group(3)) # Grupo de numero
    print(ma.group(4)) # numero

Ejemplos

Expresión regular para fechas en formato MM/DD/YYYY o MM-DD-YYYY o MM-DD-YY:

import re
re.match(r"(\d\d)[-/](\d\d)[-/](\d\d(\d\d)?)","12-12-10")

Extrae los datos de la fecha:

import re

cadena = "17 de junio de 2020"
m = re.match(r"(\d+) de (\w+) de (\d+)", cadena)
print("Dia", m.group(1))
print("Mes", m.group(2))
print("Anio", m.group(3))

Extrae los verbos (que terminan en ar, er, ir):

import re

cadena = "Tenemos que ir a comprar cosas a la tienda antes de llegar a su casa"
for f in re.findall(r"\b\w*(?:ar|er|ir)\b", cadena):
    print(f)

Solo acepta respuestas que empiecen con "Fui":

import re

respuesta = input("A donde fuiste?")

patron = r"(?:Fui)?\s([Aa]l?) (.*)"

m = re.match(patron, respuesta)
if m:
    print("Fuiste ", m.group(1), m.group(2))
else:
    print("No respondiste mi pregunta")

Ejercicios

  1. Realizar una expresión regular que valide un color en formato hexadecimal
    • validos: #fff, #ff4d4d, #660000, #1a1
    • no validos: #ff, fff, 123fff
  2. Realizar expresión regular que valide una dirección IP
    • validos: 127.0.0.1, 224.22.5.110
    • no validos: 127.0, 127..0..2

Fuentes