Regex [wtf](?:ftw)!
Jul 03, 2019
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 laa
a laz
. O -
0-9
: cualquier número del0
al9
-
\.
: 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 usara-z
-
\d
: es cualquier número, es lo mismo que usar0-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.
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 beforeJenny, I got your number
I need to make you mine
Jenny, don’t change your number867-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 disturbedJenny, I got your number
I need to make you mine
Jenny, don’t change your number867-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 callJenny, don’t change your number
I need to make you mine
Jenny, I call your number867-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, entoncess$
quiere decir que estamos buscando unas
justo antes de que termine la palabra.
Esta búsqueda nos devuelve resultados como: butyraceous
, furfuraceous
, voluptuous
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.
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 serAPA
uOPI
-
O
: En las horizontales solo puede ser[MNO]
y en las verticalesAPA
uOPI
entonces tiene que serO
-
I
: Porque en las verticales solo puede serOPI
y concide con las horizontales -
T
: las horizontales[^DJNU]
excluyen todas las letras verticales[JUNDT]
excepto laT
-
N
: es parecido al anterior solo laN
coincide entre[ICAN]
y[JUNDT]
-
D
: de igual formaD
es la única que coincide entre[DEF]
y[JUNDT]
-
N
: tenemos tres opcionesNA|FE|HE
pero solo laN
coinciden entre[MNO]
y las tres opciones -
A
: eso forza a que seaA
porque tomamos la opciónNA
-
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í:
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