Las expresiones regulares en PHP se articulan principalmente a través de dos funciones: preg_match() para comprobar si un patrón existe y capturar grupos, y preg_match_all() para encontrar todas las coincidencias de un patrón en una cadena. Ambas usan el motor PCRE (Perl Compatible Regular Expressions).
preg_match(): primera coincidencia
preg_match(string $pattern, string $subject, array &$matches = []) devuelve 1 si hay coincidencia, 0 si no la hay, y false si hay un error en el patrón:
<?php // El patrón va entre delimitadores (/ es el más habitual) $email = '[email protected]'; $resultado = preg_match('/^[w.+-]+@[w-]+.[a-z]{2,}$/i', $email); var_dump($resultado); // int(1) // Comprobar: usar === para distinguir false de 0 $resultado = preg_match('/^d{5}$/', '28001'); if ($resultado === false) { echo 'Error en el patrón'; } elseif ($resultado === 0) { echo 'Sin coincidencia'; } else { echo 'Coincidencia encontrada'; } ?>
Grupos de captura numerados
Los paréntesis crean grupos de captura. El índice 0 de $matches contiene la coincidencia completa, y desde el índice 1 en adelante los grupos capturados:
<?php
$fecha = '2026-07-22';
preg_match('/^(d{4})-(d{2})-(d{2})$/', $fecha, $matches);
echo $matches[0]; // 2026-07-22 (coincidencia completa)
echo $matches[1]; // 2026 (grupo 1: año)
echo $matches[2]; // 07 (grupo 2: mes)
echo $matches[3]; // 22 (grupo 3: día)
?>
Grupos de captura con nombre
La sintaxis (?P<nombre>...) da nombre a los grupos, haciendo el código más legible:
<?php
$url = 'https://programacion.net/articulo/php-arrays_3500';
preg_match('/^(?P<scheme>https?)://(?P<host>[w.]+)/(?P<path>.*)$/', $url, $m);
echo $m['scheme']; // https
echo $m['host']; // programacion.net
echo $m['path']; // articulo/php-arrays_3500
// También accesibles por posición
echo $m[1]; // https
echo $m[2]; // programacion.net
?>
Modificadores más usados
- i insensible a mayúsculas/minúsculas
- m multilínea:
^y$coinciden con inicio/fin de cada línea - s single-line: el punto
.también coincide con saltos de línea - u modo Unicode: el patrón y el sujeto se tratan como UTF-8
- x extended: permite espacios y comentarios en el patrón
<?php
// i: case-insensitive
preg_match('/^php$/i', 'PHP'); // 1
preg_match('/^php$/i', 'Php'); // 1
// m: multiline
$texto = "línea 1nlínea 2nlínea 3";
preg_match_all('/^línea/m', $texto, $m);
echo count($m[0]); // 3 ? coincide en cada línea
// s: el punto incluye n
preg_match('/.*?/s', '<p>textonen dos líneas</p>', $m);
// u: UTF-8
preg_match('/^w+$/u', 'café'); // 1 (con 'u'; sin él, 'é' rompe w)
?>
preg_match_all(): todas las coincidencias
<?php
$html = '<a href="https://php.net">PHP</a> y <a href="https://python.org">Python</a>';
preg_match_all('/href="([^"]+)"/', $html, $coincidencias);
// $coincidencias[0]: array de coincidencias completas
// $coincidencias[1]: array de grupos 1
print_r($coincidencias[1]);
// ['https://php.net', 'https://python.org']
?>
PREG_SET_ORDER vs PREG_PATTERN_ORDER
<?php
$texto = 'precio: 12.50, peso: 3.75, stock: 100';
preg_match_all('/(w+): ([d.]+)/', $texto, $m);
// PREG_PATTERN_ORDER (por defecto): primero todas las coincidencias completas, luego grupos
// $m[0] = ['precio: 12.50', 'peso: 3.75', 'stock: 100']
// $m[1] = ['precio', 'peso', 'stock']
// $m[2] = ['12.50', '3.75', '100']
preg_match_all('/(w+): ([d.]+)/', $texto, $m, PREG_SET_ORDER);
// PREG_SET_ORDER: agrupa por coincidencia
// $m[0] = ['precio: 12.50', 'precio', '12.50']
// $m[1] = ['peso: 3.75', 'peso', '3.75']
// $m[2] = ['stock: 100', 'stock', '100']
foreach ($m as $item) {
echo $item[1] . ' = ' . $item[2] . "n";
}
?>
El error típico: confundir false con 0
<?php
// MAL: este if pasa tanto cuando no hay coincidencia (0) como cuando hay error (false)
if (!preg_match($patron, $sujeto)) {
echo 'sin resultado';
}
// BIEN: distinguir los tres casos
$r = preg_match($patron, $sujeto, $m);
if ($r === false) {
throw new RuntimeException('Error en el patrón regex: ' . preg_last_error_msg());
} elseif ($r === 0) {
echo 'Sin coincidencia';
} else {
echo 'Encontrado: ' . $m[0];
}
?>
La documentación de preg_match() y la de preg_match_all() incluyen la referencia completa de los flags y los modificadores de patrón.
