REGEXP_LIKE
La función REGEXP_LIKE() es la versión funcional del operador REGEXP. Aunque ambos hacen lo mismo en su forma básica, REGEXP_LIKE() ofrece un tercer parámetro que permite controlar el comportamiento de la coincidencia: sensibilidad a mayúsculas, modo multilínea y tratamiento del punto con saltos de línea. Este control adicional la convierte en la opción preferida cuando necesitas ajustar cómo se interpreta el patrón.
REGEXP_LIKE() fue introducida en MySQL 8.0 como parte de la familia de funciones regulares basadas en el motor ICU, junto con REGEXP_INSTR(), REGEXP_REPLACE() y REGEXP_SUBSTR().
Sintaxis
REGEXP_LIKE(expresion, patron [, modo])El primer argumento es la cadena que se evalúa, el segundo es el patrón de expresión regular y el tercero, opcional, es una cadena con uno o más caracteres que modifican el comportamiento de la coincidencia:
| Modo | Significado |
|---|---|
'c' | Coincidencia sensible a mayúsculas y minúsculas (case-sensitive) |
'i' | Coincidencia insensible a mayúsculas y minúsculas (case-insensitive) |
'm' | Modo multilínea: ^ y $ coinciden con inicio y fin de cada línea, no solo de la cadena |
'n' | El punto (.) también coincide con caracteres de salto de línea |
'u' | Terminaciones de línea solo Unix (\n), no Windows (\r\n) |
La función devuelve 1 si hay coincidencia, 0 si no la hay y NULL si algún argumento es NULL. Puedes combinar varios caracteres de modo en una sola cadena, como 'ic' o 'mn'. Si se especifican modos contradictorios como 'ci', el último carácter prevalece.
Comportamiento básico
En su forma más simple, REGEXP_LIKE() se comporta exactamente como el operador REGEXP:
-- Estas dos consultas producen el mismo resultado
SELECT nombre FROM productos WHERE nombre REGEXP 'Samsung';
SELECT nombre FROM productos WHERE REGEXP_LIKE(nombre, 'Samsung');| nombre |
|---|
| Samsung Galaxy S24 |
| Samsung Galaxy Tab S9 |
| Samsung Monitor 32" |
La diferencia fundamental aparece cuando necesitas controlar la sensibilidad a mayúsculas. Con el operador REGEXP, debes recurrir a la palabra clave BINARY, mientras que con REGEXP_LIKE() simplemente usas el parámetro de modo:
-- Con operador REGEXP (sintaxis menos elegante)
SELECT nombre FROM productos WHERE nombre REGEXP BINARY 'samsung';
-- Con REGEXP_LIKE (sintaxis más clara)
SELECT nombre FROM productos WHERE REGEXP_LIKE(nombre, 'samsung', 'c');Ambas consultas devuelven un resultado vacío porque ningún producto tiene "samsung" en minúsculas. El modo 'c' indica coincidencia case-sensitive de forma clara y explícita.
Modo case-sensitive e case-insensitive
El modo 'c' (case-sensitive) es especialmente útil cuando trabajas con datos donde las mayúsculas son significativas, como contraseñas parciales, códigos de producto o identificadores técnicos:
SELECT nombre, codigo
FROM productos
WHERE REGEXP_LIKE(codigo, '^[a-z]', 'c');| nombre | codigo |
|---|---|
| Producto temporal | tmp-001 |
| Muestra gratuita | mue-099 |
Esta consulta encuentra productos cuyo código empieza con una letra minúscula, lo cual podría indicar productos provisionales que no siguen el estándar de códigos en mayúsculas.
El modo 'i' fuerza la comparación insensible a mayúsculas independientemente de la collation de la columna. Esto es útil cuando trabajas con columnas que tienen collation binaria o case-sensitive pero quieres ignorar la diferencia:
-- Buscar sin importar mayúsculas, incluso en columnas con collation binaria
SELECT nombre, email
FROM usuarios
WHERE REGEXP_LIKE(email, '@GMAIL\\.COM$', 'i');| nombre | |
|---|---|
| María García | maria@gmail.com |
| Carlos López | CARLOS@Gmail.Com |
| Ana Martínez | ana@GMAIL.COM |
Las tres variantes de escritura del dominio coinciden gracias al modo 'i'.
Modo multilínea
El modo 'm' cambia el comportamiento de las anclas ^ y $. Sin este modo, ^ solo coincide con el inicio de la cadena completa y $ con su final. Con el modo multilínea, estas anclas también coinciden con el inicio y fin de cada línea dentro de la cadena.
Esto es relevante cuando almacenas texto con saltos de línea en una sola columna, como direcciones, descripciones multilínea o notas:
SELECT
id,
notas,
REGEXP_LIKE(notas, '^URGENTE', 'm') AS tiene_urgente
FROM pedidos;| id | notas | tiene_urgente |
|---|---|---|
| 101 | Entregar antes del viernes\nURGENTE: cliente VIP | 1 |
| 102 | Pedido estándar | 0 |
| 103 | URGENTE: reposición de stock | 1 |
Sin el modo 'm', el pedido 101 no coincidiría porque "URGENTE" no está al inicio de la cadena completa, sino al inicio de la segunda línea. Con 'm', el ancla ^ coincide con el inicio de cada línea y la búsqueda es exitosa.
Otro ejemplo práctico sería buscar líneas específicas dentro de un campo de texto estructurado:
-- Buscar descripciones que tengan alguna línea que empiece por "Incluye:"
SELECT nombre, descripcion
FROM productos
WHERE REGEXP_LIKE(descripcion, '^Incluye:', 'm');| nombre | descripcion |
|---|---|
| Pack gaming completo | Teclado mecánico RGB\nIncluye: ratón y alfombrilla |
| Kit de herramientas | 50 piezas profesionales\nIncluye: maletín de transporte |
Modo dot-matches-newline
Por defecto, el metacarácter punto (.) coincide con cualquier carácter excepto el salto de línea. El modo 'n' cambia este comportamiento para que el punto también coincida con \n:
-- Sin modo 'n': el punto no cruza líneas
SELECT REGEXP_LIKE('primera\nsegunda', 'primera.segunda') AS sin_n;
-- Con modo 'n': el punto coincide con el salto de línea
SELECT REGEXP_LIKE('primera\nsegunda', 'primera.segunda', 'n') AS con_n;| sin_n |
|---|
| 0 |
| con_n |
|---|
| 1 |
Este modo es útil cuando necesitas que un patrón abarque múltiples líneas dentro de un campo de texto.
Combinación de modos
Puedes combinar varios caracteres de modo en una sola cadena. El orden no importa, salvo cuando hay modos contradictorios:
-- Multilínea + insensible a mayúsculas
SELECT nombre, notas
FROM pedidos
WHERE REGEXP_LIKE(notas, '^urgente', 'mi');| nombre | notas |
|---|---|
| Pedido 101 | Entregar antes del viernes\nURGENTE: cliente VIP |
| Pedido 103 | urgente: reposición de stock |
| Pedido 107 | Nota interna\nUrgente: confirmar dirección |
La combinación 'mi' activa tanto el modo multilínea como la insensibilidad a mayúsculas. El patrón ^urgente coincide con "URGENTE", "urgente" y "Urgente", tanto al inicio de la cadena como al inicio de cualquier línea.
Si combinas 'c' e 'i' en la misma cadena de modo, prevalece el último:
-- 'ci' -> prevalece 'i' (insensible)
SELECT REGEXP_LIKE('ABC', 'abc', 'ci') AS resultado;| resultado |
|---|
| 1 |
Caso práctico: auditoría de datos de usuarios
En un sistema donde los usuarios ingresan datos manualmente, REGEXP_LIKE() es ideal para auditar la calidad de la información. Veamos cómo detectar problemas comunes:
SELECT
id,
nombre,
CASE
WHEN NOT REGEXP_LIKE(nombre, '^[A-ZÁÉÍÓÚÑ]', 'c')
THEN 'No empieza por mayúscula'
WHEN REGEXP_LIKE(nombre, '[0-9]')
THEN 'Contiene números'
WHEN REGEXP_LIKE(nombre, ' ')
THEN 'Espacios dobles'
WHEN REGEXP_LIKE(nombre, '(^\\s|\\s$)')
THEN 'Espacios al inicio o final'
ELSE 'OK'
END AS problema
FROM clientes
WHERE NOT REGEXP_LIKE(nombre, '^[A-ZÁÉÍÓÚÑ][a-záéíóúñ]+ [A-ZÁÉÍÓÚÑ][a-záéíóúñ]+', 'c')
ORDER BY problema;| id | nombre | problema |
|---|---|---|
| 15 | carlos lópez | No empieza por mayúscula |
| 23 | María García2 | Contiene números |
| 31 | Ana Martínez | Espacios dobles |
| 42 | Pedro Ruiz | Espacios al inicio o final |
El modo 'c' es esencial aquí porque necesitamos distinguir entre mayúsculas y minúsculas para detectar nombres que no empiezan con mayúscula.
Caso práctico: filtrar registros con patrones complejos
Supón que tienes una tabla de pedidos con un campo de notas de texto libre y necesitas encontrar pedidos que mencionan devoluciones o cancelaciones:
SELECT
id,
fecha,
total,
notas
FROM pedidos
WHERE REGEXP_LIKE(
notas,
'(devol(ución|ver)|cancel(ación|ar|ado)|reembols(o|ar))',
'i'
);| id | fecha | total | notas |
|---|---|---|---|
| 1045 | 2025-03-15 | 89.99 | Cliente solicita devolución por defecto |
| 1078 | 2025-03-18 | 245.00 | Cancelado por falta de stock |
| 1102 | 2025-03-20 | 59.50 | Pendiente de reembolso bancario |
| 1130 | 2025-03-22 | 175.00 | Devolver al almacén central |
El patrón usa alternancia y grupos para capturar todas las variantes de las palabras relacionadas: "devolución", "devolver", "cancelación", "cancelar", "cancelado", "reembolso" y "reembolsar". El modo 'i' asegura que funcione independientemente de si el texto está en mayúsculas o minúsculas.
Manejo de NULL
REGEXP_LIKE() devuelve NULL si cualquiera de sus argumentos es NULL:
SELECT
nombre,
telefono,
REGEXP_LIKE(telefono, '^[0-9]+$') AS es_numerico,
COALESCE(REGEXP_LIKE(telefono, '^[0-9]+$'), 0) AS es_numerico_seguro
FROM clientes;| nombre | telefono | es_numerico | es_numerico_seguro |
|---|---|---|---|
| María García | 612345678 | 1 | 1 |
| Carlos López | +34-678-901-234 | 0 | 0 |
| Pedro Ruiz | NULL | NULL | 0 |
La función COALESCE convierte el NULL en 0, lo cual es útil cuando necesitas un resultado booleano garantizado para usarlo en cálculos o agregaciones.
Combinación con otras funciones
REGEXP_LIKE() se integra bien con funciones de agregación para generar informes de calidad de datos:
SELECT
COUNT(*) AS total_clientes,
SUM(REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$')) AS emails_validos,
SUM(1 - COALESCE(REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'), 0)) AS emails_invalidos,
ROUND(
100.0 * SUM(REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$'))
/ COUNT(*),
1
) AS porcentaje_validos
FROM clientes;| total_clientes | emails_validos | emails_invalidos | porcentaje_validos |
|---|---|---|---|
| 250 | 237 | 13 | 94.8 |
Este tipo de consulta es invaluable para medir la calidad de los datos antes de una migración o para un informe periódico de integridad.
También puedes usarla en restricciones CHECK (MySQL 8.0.16+) para validar datos al insertarlos:
CREATE TABLE usuarios_v2 (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(255) NOT NULL,
telefono VARCHAR(20),
codigo_postal VARCHAR(10),
CONSTRAINT chk_email CHECK (
REGEXP_LIKE(email, '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$')
),
CONSTRAINT chk_telefono CHECK (
telefono IS NULL OR REGEXP_LIKE(telefono, '^(\\+34)?[6-9][0-9]{8}$')
),
CONSTRAINT chk_cp CHECK (
codigo_postal IS NULL OR REGEXP_LIKE(codigo_postal, '^[0-5][0-9]{4}$')
)
);Con estas restricciones, MySQL rechazará automáticamente cualquier inserción o actualización que no cumpla los patrones definidos, asegurando la integridad de los datos desde la propia base de datos.
En el siguiente artículo veremos REGEXP_INSTR para encontrar la posición de una coincidencia.
Escrito por Eduardo Lázaro
