Expresiones regulares en JavaScript

Las expresiones regulares buscan patrones dentro de un texto: validar un correo, extraer fechas, limpiar espacios. En JavaScript se escriben entre barras, /patrón/banderas, y se usan con métodos de las cadenas.

Comprobar si un texto encaja

const correo = /^[^\s@]+@[^\s@]+\.[a-z]{2,}$/i;
for (const c of ["ana@ejemplo.com", "ANA@EJEMPLO.MX", "ana@ejemplo", "ana @ejemplo.com"]) {
  console.log(c.padEnd(18), correo.test(c));
}
salidaana@ejemplo.com    true
ANA@EJEMPLO.MX     true
ana@ejemplo        false
ana @ejemplo.com   false

test devuelve true o false. Los anclajes ^ y $ obligan a que encaje el texto entero y no solo un trozo, y la bandera i ignora mayúsculas. Esta expresión es deliberadamente sencilla: comprueba la forma de un correo, no que exista.

Extraer partes: grupos con nombre

const texto = "Pedido 1042 del 2026-10-19, pedido 1043 del 2026-10-21.";

const fecha = /(?<anio>\d{4})-(?<mes>\d{2})-(?<dia>\d{2})/;
const m = texto.match(fecha);
console.log(m[0], "|", m.groups.dia, m.groups.mes, m.groups.anio, "| en la posición", m.index);

console.log(texto.match(/\d{4}-\d{2}-\d{2}/g));

for (const { groups, index } of texto.matchAll(/pedido (?<num>\d+)/gi)) {
  console.log(`pedido ${groups.num} en la posición ${index}`);
}

console.log(texto.replace(/(?<a>\d{4})-(?<m>\d{2})-(?<d>\d{2})/g, "$<d>/$<m>/$<a>"));
salida2026-10-19 | 19 10 2026 | en la posición 16
[ '2026-10-19', '2026-10-21' ]
pedido 1042 en la posición 0
pedido 1043 en la posición 28
Pedido 1042 del 19/10/2026, pedido 1043 del 21/10/2026.

Cómo se reparten los grupos con nombre de una expresión regular sobre una fechaGrupos con nombre en una expresión regular/(?<anio>\d{4})-(?<mes>\d{2})-(?<dia>\d{2})/Pedido 1042 del 2026groups.anio–10groups.mes–19groups.dia, pedido…m[0]: la coincidencia enteram.index vale 16: la posición donde empieza la coincidencia.

Cada grupo (?<nombre>...) captura un trozo de la coincidencia y lo deja en groups. Esquema: decodigo.com.

Tres formas de buscar, según lo que quieras:

MétodoQué devuelve
texto.match(/.../)La primera coincidencia, con sus grupos e index
texto.match(/.../g)Solo los textos de todas las coincidencias, sin grupos
texto.matchAll(/.../g)Todas las coincidencias, cada una con grupos e index

Y en replace, $<nombre> se sustituye por lo que capturó ese grupo: así se reordena una fecha en una línea.

Reemplazar con una función, y otros usos

const precios = "Teclado 49.9, ratón 19.5, monitor 189";
const conIva = precios.replace(/\d+(\.\d+)?/g, (n) => (Number(n) * 1.16).toFixed(2));
console.log(conIva);

console.log("a-b_c d".split(/[-_ ]/));
console.log("  muchos    espacios   aquí ".trim().replace(/\s+/g, " "));

console.log("1.5".replace(".", ","), "|", "1.5.0".replaceAll(".", ","));
console.log("x.y.z".replace(/./g, "*"));
salidaTeclado 57.88, ratón 22.62, monitor 219.24
[ 'a', 'b', 'c', 'd' ]
muchos espacios aquí
1,5 | 1,5,0
*****

Si el segundo argumento de replace es una función, se llama con cada coincidencia y lo que devuelva la sustituye. Las dos últimas líneas muestran dos detalles: replace con una cadena cambia solo la primera aparición (para todas está replaceAll), y en una expresión el punto significa «cualquier carácter»: por eso /./g lo tapa todo.

Acentos y eñes: la bandera u

const palabra = /^\w+$/;
console.log(palabra.test("cafe"), palabra.test("café"), palabra.test("año"));

const letras = /^\p{L}+$/u;
console.log(letras.test("cafe"), letras.test("café"), letras.test("año"));
salidatrue false false
true true true

\w solo reconoce letras inglesas: ni «é» ni «ñ» son para él caracteres de palabra. Con la bandera u se pueden usar categorías de Unicode, y \p{L} significa «cualquier letra de cualquier idioma». Para textos en español, es la que conviene.

La trampa de lastIndex

const esNumero = /\d+/g;
console.log(esNumero.test("abc 123"), esNumero.lastIndex);
console.log(esNumero.test("abc 123"), esNumero.lastIndex);
console.log(esNumero.test("abc 123"), esNumero.lastIndex);
salidatrue 7
false 0
true 7

El mismo test sobre el mismo texto da true, luego false, y luego otra vez true. Con la bandera g, la expresión recuerda en lastIndex dónde se quedó y la siguiente búsqueda empieza ahí. Regla práctica: no uses g con test; solo hace falta para buscar todas las coincidencias.

Buscar un texto literal: RegExp.escape

Si construyes una expresión a partir de lo que escribe el usuario, sus paréntesis, puntos y signos + se interpretan como parte del patrón. Un paréntesis sin cerrar ni siquiera compila:

new RegExp("precio (USD")SyntaxError: Invalid regular expression: /precio (USD/: Unterminated group

RegExp.escape, recién llegado al lenguaje y ya disponible en Node 24, escapa todo lo necesario:

const buscado = "1+1 (suma)";
const exacto = new RegExp(RegExp.escape(buscado));
console.log(exacto.source);
console.log(exacto.test("¿Cuánto es 1+1 (suma)?"));
console.log(new RegExp(buscado).test("¿Cuánto es 1+1 (suma)?"));
salida\x31\+1\x20\(suma\)
true
false

La primera línea parece rara pero es correcta: también escapa el primer dígito y los espacios, como \x31 y \x20, para que el resultado sea seguro en cualquier posición del patrón. La última línea muestra lo que pasa sin escapar: el + y los paréntesis cambian el significado y la búsqueda falla.

En navegadores antiguos, RegExp.escape no existe. Si tu código tiene que funcionar en ellos, la alternativa clásica es texto.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), que escapa los caracteres especiales uno a uno.

Todo el código de esta página se ejecutó con Node.js 24.22 en un contenedor limpio antes de publicarla; las salidas, incluidos los errores, están copiadas de esa ejecución. Documentación oficial: la guía de expresiones regulares de MDN.