Expresiones regulares
Las expresiones regulares son todo un caso en las ciencias de la computación por su estrecha relación que tienen con la teoría de autómatas y todas las implicaciones que eso conlleva. Sin embargo, ahora no nos vamos a meter con eso y solamente vamos a ver la punta del iceberg.
El término surgió a mediados de los 50’s y fue creado por el matemático Stephen Cole Kleene, y se refiere a secuencias de caracteres que definen patrones de búsqueda, es por eso que a veces también se les conoce simplemente como patrones.
Estos patrones están definidos bajo tres operaciones básicas:
Alternación
Que se define por un pipe (una barra vertical), y que es un or
que le indicará al patrón que una coincidencia se da entre cualquiera de los elementos que aparezcan a sus lados: por ejemplo, una expresión de este tipo:
Cuantificación
Se usa para especificar la cantidad de ocurrencias de determinado elemento. La operación de cuantificación cuenta con varios operadores:
Primero tenemos el signo de interrogación, ?
, que indicará que el elemento que la antecede puede aparecer cero o una sola vez.
Después tenemos el cierre u operador estrella, *
, que indica que el elemento que la antecede puede repetirse 0 o más veces.
Y por último tenemos el operador cierre positivo +
que es parecido al operador estrella, solo que en este caso debe existir al menos una ocurrencia del elemento que la precede.
Sin embargo estos operadores de cuantificación son muy permisivos: es decir tenemos 0 o uno, 0 o más, y 1 o más, pero si queremos poner límites un poco más estrictos podemos utilizar los corchetes (o llaves) {
}
que permiten especificar con enteros el número de repeticiones que queremos encontrar, entonces podemos usarlas así:
Un solo número entre las llaves {n}
para especificar que esperamos exactamente n
ocurrencias, del elemento que la precede.
Un solo número seguido de una coma {n,}
que indica que esperamos al menos n
ocurrencias y que puede haber más.
Después tenemos dos números separados por una coma {n,m}
que especifica que esperamos al menos n
y a lo mucho m
ocurrencias de un elemento.
Agrupación
Para la cual se utilizan los paréntesis (
)
, y como el nombre lo indica: sirve para agrupar, tiene más sentido cuando se usa en combinación con los dos anteriores. Por ejemplo, podemos especificar una agrupación empleando el operador de alternación:
O una usando los operadores de cuantificación:
E inclusive se pueden crear las combinaciones más extrañas que puedas imaginar:
Implementaciones de las regex
Ahora, estos son los conceptos básicos detrás de ellas, sin embargo, dependiendo de su implementación bajo determinado estándar o lenguaje de programación, las regex suelen tener también una sintaxis específica y un conjunto de metacaracteres que las dotan de mayor funcionalidad, tomemos por ejemplo el caso de un pseudo-estándar llamado PCRE (Perl-Compatible Regular Expressions). Sí, es un estándar definido por el lenguaje de programación Perl, a partir del cual muchas otras implementaciones en otros lenguajes se han basado.
Caracteres de escape
Para los cuales se usa la barra invertida \
para escapar caracteres especiales como tabuladores \t
, saltos de línea \n
y caracteres unicode \u0020
Clases de caracteres
Que se representan dentro de corchetes cuadrados []
para especificar conjuntos de caracteres como este [aeiou]
que reconocerá todas las vocales individualmente. Aunque el mejor uso de las clases es para especificar rangos, por ejemplo, podrías tener una expresión regular como esta [a-zA-Z0-9]
que reconocerá todas las letras minúsculas, mayúsculas y números. Además de que las clases de caracteres también tienen un operador de negación (el acento circunflejo), como en la siguiente expresión [^0-5]
que reconocerá todo, menos los números del 0 al 5.
Anclas
Luego tenemos las anclas, que son especificaciones sobre la ubicación de los patrones de búsqueda, en este caso aparece nuevamente el acento circunflejo, ^
que cuando no está dentro de la definición de una clase de caracteres, indica que el patrón a buscar debe estar siempre al inicio de la cadena, toma como ejemplo este: ^[0-9]+
que encontrará solo los números que estén al inicio de una cadena. Por otra parte tenemos el símbolo de dólar $
que indica que el patrón a buscar debe ocurrir siempre al final de la cadena, por ejemplo este [0-9]+$
que encontrará todos los números al final. Cabe destacar que estos son combinables, para crear un patrón que encontrará líneas que solamente contengan números:
En este video me limité por cuestiones de tiempo, pero pueden leer más aquí: PCRE Regex Cheatsheet, otro cheatsheet y POSIX Basic Regular Expressions y RegexOne, un lugar para aprender a trabajar con ellas.
Aplicaciones
Probablemente ya te hayas encontrado o estés pensando en las posibles aplicaciones de estas expresiones, y la mayoría tienen que ver con procesamiento de cadenas de texto, pero aquí hay algunas:
-
Obtención de datos: se pueden crear patrones que busquen cierta información dentro de un documento, como el caso del comando
grep
en sistemas basados en UNIX que significa “búsqueda global e impresión de expresiones regulares” que permite buscar texto en documentos. -
Validación de datos: para saber si estás introduciendo los datos (al menos estructuralmente) adecuados en un formulario. Las validaciones de email, números de teléfono, códigos postales, tarjetas de crédito… y he visto que, en algunos casos, para la validación de contraseñas, están hechas con expresiones regulares.
-
Búsqueda y reemplazo de valores: las expresiones regulares hacen más sencilla esta tarea, yo tengo un buen ejemplo con esto: en el código de una aplicación en la que estuve trabajando había muchos bloques try con catches vacíos, entonces mediante una expresión regular reemplazamos estos catches vacíos por instrucciones de logging y voilà, no más mal código. ¿Tú las has usado en algo? déjalo en los comentarios.