Regex [wtf](?:ftw)!

Jul 03, 2019

Pattern tiles

Es hora de hablar de Expresiones Regulares: regex. Una expresión regular es un patrón que podemos utilizar para encontrar coincidencias dentro de textos, por ejemplo, encontrar un teléfono dentro de un mensaje de texto. Son una de las herramientas más útiles que aprender para usar en tu día a día.

Para experimentar vamos a utilizar:

  • regex101.com, porque nos permite compartir y guardar ejercicios y probar con diferentes sabores de regex.
  • regexdict porque podemos hacer búsquedas con regex
  • y regexcrossword porque es genial

El modo en que se emplee en tu lenguaje de programación va a variar, pero en general tu regex va a funcionar; casi todos los lenguajes son “Pearl compatible”

Vamos a hacer cuatro ejercicios (a) validar un email (b) identificar un teléfono (c) encontrar todas las palabras en ingles con un patrón (d) resolver un crucigrama de regex. Espero que estos ejercicios te den una idea de las muy amplias capacidades de utilizar expresiones regulares.

(a) Validar un email

Cuando estas haciendo un sistema muchas veces necesitas validar que el email de un usuario tenga sentido, para que se les pueda enviar correo. Un email en general son letras, números, algo de puntuación, una @ y un dominio. Esto lo podemos lograr con esta expresión [a-z0-9\.-_]+@[\w\d]+\.\w+ que significa:

  • [a-z0-9\.-_]: Los corchetes [] hacen que seleccionemos algo de lo que hay adentro de esos corchetes. En este caso
  • a-z: cualquier letra de la a a la z. O
  • 0-9: cualquier número del 0 al 9
  • \.: un punto. tenemos que poner la diagonal porque el punto usualmente significa otra cosa, literalmente cualquier otra cosa (lee los siguientes ejemplos)
  • -: es un guión. Nota que aquí es un guión, pero si lo rodeamos de números o letras, como arriba, significa un rango
  • _: un guión bajo
  • +: significa que queremos que el grupo anterior aprezca una o más veces. Entonces podemos tener cualquier combinación, por ejemplo: aiu123, 12__abc o .a.z.8, etc.
  • @: es una arroba!
  • [\w\d]+ es otra forma de escribir algo similar al grupo anterior
  • \w: es cualquier letra, es lo mismo que usar a-z
  • \d: es cualquier número, es lo mismo que usar 0-9
  • \.\w+: es un punto, seguido de cualquier combinación de letras.

Desde luego esta no es la mejor expresión pero es un punto de partida. Tiene algunos problemas, como que permite cualquier top level domain exista o no, por ejemplo i@example.perro y no permite top levels compuestos por ejemplo i@example.com.mx no sería un correo válido con esta expresión.

Puedes ver otros ejemplos de correos que validan y no validan con esta expresión en regex101 ¿Qué puedes hacer para que esta expresión sea mejor?

(b) Identificar un teléfono

Vamos a extraer el Teléfono Jenny, de 867-5309/Jenny una canción ochentera de Tommy Tutone que puedes escuchar abajo.

867-5309/Jenny

Jenny, Jenny, who can I turn to?
You give me somethin’ I can hold on to
I know you think I’m like the others before

Jenny, I got your number
I need to make you mine
Jenny, don’t change your number

867-5309

Jenny, Jenny, you’re the girl for me
Oh, you don’t know me, but you make me so happy
I tried to call you before, but I lost my nerve
I tried my imagination, but I was disturbed

Jenny, I got your number
I need to make you mine
Jenny, don’t change your number

867-5309

I got it, (I got it), I got it
I got your number on the wall
I got it, (I got it), I got it
For a good time, for a good time call

Jenny, don’t change your number
I need to make you mine
Jenny, I call your number

867-5309

Jenny, Jenny, who can I turn to?
867-5309
For the price of a dime I can always turn to you
867-5309

La expresión que vamos a utilizar es \d{3}-\d{4}

  • \d{3} y \d{4} significa que vamos a buscar 3 o 4 dígitos dependiendo.
  • - significa que estamos buscando un guión

En conjunto estamos buscando 3 dígitos seguidos de un guión seguidos de 4 dígitos. De modo que esta expresión no encontraría algo como 86-5309 o 867 5309. Pero si econtraría el número aunque estuviera rodeado de otro texto, por ejemplo abc867-5309def porque no tenemos ninguna restricción respecto a que va a antes o después de nuestro match

Puedes ver el ejercio (a) en regex101 aquí y probar los ejemplos alternativos

(c) Encontrar todas las palabras en inglés con un patrón

Para este ejercicio vamos a usar un diccionario en el que se puede buscar utilizando expresiones regulares, pero igual podrías descargar una lista de todas las palabras en ingles y utilizar el lenguaje de tu preferencia.

Este ejercicio es útil para resolver crucigramas, algun otro tipo de acertijos o… para buscar ciertos patrones en tu código. Vamos a buscar todas las palabras en ingles que empiecen con una consonante, en algún punto tengan un triptongo, terminen con una s.

La expresión es [^aiueo].*[aiueo]{3}.*s$ que significa:

  • [aiueo] los corchetes significan que estamos buscando alguno de los caracteres que estan dentro de los corchetes, solo uno de ellos. En este caso significa cualquier vocal.
  • [^aiueo] cuando lo primero que hay dentro es un ^ significa que no queremos ninguno de los caracteres que hay dentro [] y [^] son expresiones contrarias. Aquí quiere decir que no queremos ninguna vocal.
  • [aiueo]{3} significa que queremos esos caracteres repetidos tres veces, que es cualquier triptongo, por ejemplo: aaa, auo, ooa etc.
  • .* es cualquier cosa, literalmente cualquier cosa repetida cualquier número de veces incluso cero veces.
  • $ significa el final de la linea, entonces s$ quiere decir que estamos buscando una s justo antes de que termine la palabra.

Esta búsqueda nos devuelve resultados como: butyraceous, furfuraceous, voluptuous

Busqueda por regex

Puedes probar la expresión en regexdict y ¿por qué no intentar buscar todas las palabras que tengan una xs y que esten seguidas de otra consonante? ¡resulta que solo hay tres!

(d) Resolver un crucigrama de regex

Este es el ejemplo menos útil pero más divertido si te tomas el tiempo de aprender expresiones regulares.

Regex crossword

Voy a explicar este crucigrama a partir de cómo lo resolví yo.

  • P: En las horizontales esta la P explícita, entonces solo puede ser la P. En las verticales entonces solo puede ser APA u OPI
  • O: En las horizontales solo puede ser [MNO] y en las verticales APA u OPI entonces tiene que ser O
  • I: Porque en las verticales solo puede ser OPI y concide con las horizontales
  • T: las horizontales [^DJNU] excluyen todas las letras verticales [JUNDT] excepto la T
  • N: es parecido al anterior solo la N coincide entre [ICAN] y [JUNDT]
  • D: de igual forma D es la única que coincide entre [DEF] y [JUNDT]
  • N: tenemos tres opciones NA|FE|HE pero solo la Ncoinciden entre [MNO] y las tres opciones
  • A: eso forza a que sea A porque tomamos la opción NA
  • C: es la única letra que coincide entre [ICAN] y [CV]

Hay muchos más crucigramas en regexcrossword algunos de los cuales se ven así:

Hard Crossword


Espero este post haya despertado tu interés por aprender sobre expresiones regulares, las puedes utilizar todos los días al momento de desarrollar, seguramente tu editor soporta búsquedas por regex. Y hay muchos problemas que se resuelven fácilmente mediante expresiones regulares.

Si te gustó puedes aprender más en la documentación de python, donde que hace cada patrón esta muy bien explicado. Y si ya vas a programar en python te invito a ver mi post anterior sobre pipenv que es una herramienta que vas a estar utilizando mucho.

Pd. Gracias a @aalkz por la idea del post.

– Anya Reyes