Cómo crear expresiones regulares

Carácteres especiales dentro de las expresiones regulares

Crear expresiones regulares puede parecer fácil al principio, sin embargo, es muy fácil crear expresiones regulares que tengan resultados no previstos, por lo que hay que practicar mucho y tener cierta experiencia con ellas.

Antes de comenzar a crear expresiones regulares hay que aprender bien quizás la parte más compleja: los carácteres o símbolos especiales que poseen. Ciertos carácteres tienen un significado especial dentro de las expresiones regulares, e incluso, muchos de ellos dependen de donde se encuentren para tener ese significado especial.

Clases básicas

Empecemos con algunos de los más sencillos:

Caracter especial Descripción
. Comodín, significa cualquier caracter (letra, número, símbolo...), pero que ocupe sólo 1 carácter.
\ Precedido de un carácter especial, lo invalida (se llama «escapar»).

En esta pequeña tabla vemos los caracteres especiales más básicos por lo que podemos partir para aprender expresiones regulares. Veamos algunos ejemplos aplicándolos:

const regexp = /M.nz/;

regexp.test("Manz"); // true (el texto "Manz" encaja con el patrón)
regexp.test("manz"); // false (La «M» debe ser mayúscula)

const regexp = /M.nz/i;

regexp.ignoreCase // true
regexp.test("manz"); // true (ignoramos mayús/minús con el flag «i»)

Como puedes ver, el . se utiliza como símbolo o carácter especial y significa «cualquier carácter». No obstante, podríamos añadir un \ antes del ., y así escapar el punto y que en lugar de tener un significado especial (cualquier carácter) tenga el significado literalmente un punto:

const regexp = /gato./;

regexp.test("gatos."); // true
regexp.test("gatosa"); // true
regexp.test("gatos "); // true

const regexp = /gato\./;

regexp.test("gatos."); // true (es literalmente el punto)
regexp.test("gatosa"); // false
regexp.test("gatos "); // false

El escapado de carácteres es esencial en las expresiones regulares, ya que es frecuente necesitar utilizarlo.

Conjunto de carácteres

Dentro de las expresiones regulares, los corchetes [] tienen un significado especial. Se trata de un mecanismo para englobar un conjunto de carácteres personalizado o alternativas. Pero por otro lado, si incluimos un circunflejo ^ en el interior de los corchetes, invertimos el significado, pasando a significar que no exista el conjunto de carácteres personalizado:

Caracter especial Descripción
[] Rango de carácteres. Cualquiera de los caracteres del interior de los corchetes.
[^] Que no exista cualquiera de los caracteres del interior de los corchetes.
| Establece una alternativa: lo que está a la izquierda o lo que está a la derecha.

Por último, tenemos el «pipe» |, con el que podemos establecer alternativas. Veamos un ejemplo aplicado a esto, para que se verá más claro:

const regexp = /[aeiou]/i;    // RegExp que acepta vocales (mayús/minús)

regexp.test("a"); // true (es vocal)
regexp.test("E"); // true (es vocal, ignora mayus/minus porque tiene flag «i»)
regexp.test("t"); // false (no es vocal)

const regexp = /[^aeiou]/i; // RegExp que acepta lo que no sea vocal (mayús/minús)

regexp.test("a"); // false
regexp.test("E"); // false
regexp.test("T"); // true
regexp.test("m"); // true

const regexp = /casa|cama/; // RegExp que acepta "casa" o "cama"

regexp.test("casa"); // true
regexp.test("cama"); // true
regexp.test("capa"); // false

const regexp = /cas(i|o)ta/; // RegExp que acepta "casita" o "casota"

regexp.test("casita"); // true
regexp.test("casota"); // true
regexp.test("caseta"); // false

Como se puede ver, con los paréntesis () puedes agrupar una parte más específica para indicar alternativas, aunque recuerda que con los paréntesis estás haciendo capturas de textos con Expresiones regulares.

Rangos de carácteres

En el interior de los corchetes [], si establecemos dos carácteres separados por guión, por ejemplo [0-9], se entiende que indicamos el rango de carácteres entre 0 y 9, sin tener que escribirlos todos explícitamente.

De esta forma podemos crear rangos como [A-Z] (una letra mayúscula) o [a-z] (una letra minúscula), o incluso varios rangos como [A-Za-z0-9] (una letra mayúscula, minúscula o un dígito del 0 al 9):

Caracter especial Alternativa Descripción
[0-9] \d Un dígito del 0 al 9.
[^0-9] \D No exista un dígito del 0 al 9.
[A-Z] Letra mayúscula de la A a la Z. Excluye ñ o letras acentuadas.
[a-z] Letra minúscula de la a a la z. Excluye ñ o letras acentuadas.
[A-Za-z0-9] \w Carácter alfanumérico (letra mayúscula, minúscula o dígito).
[^A-Za-z0-9] \W No exista carácter alfanumérico (letra mayúscula, minúscula o dígito).
[ \t\r\n\f] \s Carácter de espacio en blanco (espacio, TAB, CR, LF o FF).
[^ \t\r\n\f] \S No exista carácter de espacio en blanco (espacio, TAB, CR, LF o FF).
\xN Carácter hexadecimal número N.
\uN Carácter Unicode número N.

En las expresiones regulares podemos tanto escribir el caracter especial como la notación alternativa, que son equivalentes y significan lo mismo. Por ejemplo, es lo mismo escribir [0-9] que \d. Algunos programadores encuentran más explicativa la primera forma y otros más cómoda la segunda.

Anclas

Hay algo importante que hemos omitido hasta ahora. Dentro de las expresiones regulares, las anclas son un recurso muy importante, ya que permiten delimitar los patrones de búsqueda e indicar si empiezan o terminan por carácteres concretos, siendo mucho más específicos al realizar la búsqueda:

Caracter especial Descripción
^ Ancla. Delimita el inicio del patrón. Significa empieza por.
$ Ancla. Delimita el final del patrón. Significa acaba en.
\b Límite de una palabra separada por espacios, puntuación o inicio/final.
\B Opuesta al anterior. Posición entre 2 caracteres alfanuméricos o no alfanuméricos.

Para entender esto bien, veamos varios ejemplos. En los primeros ejemplos vamos a aplicar las anclas ^ y $ en la expresión regular para delimitar el inicio y el final de un texto:

const regexp = /^mas/i;     // Debe empezar por "mas"

regexp.test("Formas"); // false (contiene "mas", pero no empieza por "mas")
regexp.test("Master"); // true (empieza por "mas" y tiene el flag «i»)
regexp.test("masticar"); // true

const regexp = /do$/i; // Debe terminar por "do"

regexp.test("Vívido"); // true
regexp.test("Dominó"); // false (contiene "do" pero no acaba por "do")

Por otro lado, si utilizamos \b se nos permite indicar si el texto adyacente está seguido (o precedido) de un límite de palabra (espacio), puntuación (comas o puntos) o inicio o final del :

const regexp = /fo\b/;

regexp.test("Esto es un párrafo de texto."); // true (tras "fo" hay un límite de palabra)
regexp.test("Esto es un párrafo."); // true (tras "fo" hay un signo de puntuación)
regexp.test("Un círculo es una forma."); // false (tras "fo" sigue la palabra)
regexp.test("Frase que termina en fo"); // true (tras "fo" termina el string)

Por último, \B es la operación opuesta a \b, por lo que podemos utilizarla cuando nos interesa que el texto no esté delimitado por una palabra, puntuación o string en sí.

Cuantificadores

En las expresiones regulares los cuantificadores permiten indicar cuántas veces se puede repetir el carácter inmediatamente anterior. Existen varios tipos de cuantificadores:

Caracter especial Descripción
* El carácter anterior puede aparecer 0 o más veces.
+ El carácter anterior puede aparecer 1 o más veces.
? El carácter anterior puede aparecer o no (es opcional).
{n} El carácter anterior aparece n veces.
{n,} El carácter anterior aparece n o más veces.
{n,m} El carácter anterior aparece de n a m veces.

Veamos algunos ejemplos para aprender a aplicarlos. Comencemos con el primero, el caracter especial * (0 o más veces):

const regexp = /a*/;   // 'a' aparece 0 o más veces en el string

regexp.test(""); // true ('a' aparece 0 veces)
regexp.test("a"); // true ('a' aparece 1 veces)
regexp.test("aa"); // true ('a' aparece 2 veces)
regexp.test("aba"); // true ('a' aparece 2 veces)
regexp.test("bbb"); // true ('a' aparece 0 veces)

El cuantificador + es muy parecido al cuantificador * anterior, sólo que con el cuentificador + es necesario que el carácter anterior aparezca al menos una vez, al contrario que con * que permitía que no apareciera:

const regexp = /a+/;    // 'a' aparece 1 o más veces (equivalente a /aa*/)

regexp.test(""); // false ('a' aparece 0 veces)
regexp.test("a"); // true ('a' aparece 1 veces)
regexp.test("aa"); // true ('a' aparece 2 veces)
regexp.test("aba"); // true ('a' aparece 2 veces)
regexp.test("bbb"); // false ('a' aparece 0 veces)

Por otro lado, el cuantificador ? se suele utilizar para indicar que el carácter anterior es opcional (puede aparecer o puede no aparecer). Normalmente se utiliza cuando quieres indicar que no importa que aparezca un carácter opcional:

const regexp = /disparos?/i;      // Acepta tanto "disparo" como "disparos"

regexp.test("Escuché disparos en la habitación."); // true
regexp.test("Efectuó un disparo al sujeto."); // true
regexp.test("La pistola era de agua."); // false

Esto nos permite establecer carácteres opcionales de forma muy sencilla y cómoda.

Cuantificadores numéricos

Los tres cuantificadores siguientes, se utilizan cuando necesitamos concretar más el número de repeticiones del caracter anterior. Por ejemplo, {n} indica un número exacto, {n,} indica al menos n veces y {n,m} establece que se puede repetir de n a m veces:

const regexp = /[0-9]{2}/;    // Un número formado por 2 dígitos (del 0 al 9)

regexp.test(42); // true
regexp.test(88); // true
regexp.test(1); // false (no son 2 dígitos)
regexp.test(100); // true (tiene al menos 2 dígitos)

Observa que el último aparece como true. Esto ocurre porque en la expresión regular no se han establecido anclas que delimiten el inicio y/o el final del texto. Si las añadimos, es más estricto con las comprobaciones:

const regexp = /^[0-9]{2}$/;    // Un número de exactamente 2 dígitos (del 0 al 9)

regexp.test(4); // false (no llega a 2 dígitos)
regexp.test(55); // true
regexp.test(100); // false (no tiene exáctamente 2 dígitos)

const regexp = /^[0-9]{3,}$/;

regexp.test(33); // false (debe tener al menos 3 dígitos)
regexp.test(4923); // true

const regexp = /^[0-9]{2,5}$/;

regexp.test(2); // false (no tiene de 2 a 5 dígitos)
regexp.test(444); // true
regexp.test(543213); // false (no tiene de 2 a 5 dígitos)

Si quieres profundizar con las expresiones regulares, puedes jugar a RegEx People, un pequeño y básico juego para aprender a utilizar las expresiones regulares y buscar patrones, con su código fuente disponible en GitHub.

Tabla de contenidos