007a Más strings: Expresión regular
"Una expresión regular ... es una secuencia de caracteres que conforma un patrón de búsqueda."
-- Wikipedia, Expresión regular
Desde que ha habido texto en las computadoras, ha existido la necesidad de poder buscar por ese texto. A través del tiempo, se ha desarrollado una combinación de patrones sofisticada. Llamamos esta búsqueda por patrones "expresiones regulares" o regex. Es una idea bien entendida en informática y es una forma muy rápida de buscar en el texto.
Hay varias maneras fundamentales para hacer regex, pero en PHP moderno, sólo se usa uno: expresión regular estilo de Perl. El idioma de programación de Perl desarrolló esta manera y es popular entre muchos idiomas de programación. Por eso el nombre formal es "Perl Compatible Regular Expressions" (Expresiones regulares compatibles con Perl) o PCRE. Hay una familia de funciones relacionadas para hacer regex, y todas empiezan con el prefijo "preg_".
Conceptos básicos
Una expresión regular (también llamado un patrón) es un string que se puede usar para encontrar una(s) coincidencia(s) dentro de otro string. En general, hay algunos tipos de operaciones usadas para construir expresiones regulares:
"o" booleano
Una barra vertical o "pleca" para separar opciones. Así el patrón buey|güey
puede coincidir con o "buey" o "güey".
Grupos
Un grupo se hace con paréntesis "()" y se usa para tratar a varias fichas juntas. Usando grupos, se puede lograr el mismo coincidir del patrón anterior: (bu|gü)ey
también coincide con "buey" o "büey". Igual, M(é|e)xico
coincide con "México" y "Mexico".
Cuantificación
Cuantificadores siguen un elemento y especifiquen cuantas veces ese elemento debe de repetir. Por ejemplo:
?
- indica 0 o 1 ocurrencias del elemento.casas?
coincide con "casa" y "casas"*
- indica 0 o más ocurrencias del elemento.(gra-)*cias
coincide con "gra-cias" y "gra-gra-cias" y "gra-gra-gra-gra-gra-cias" y así sucesivamente.+
- indica 1 o más ocurrencias del elemento. AsíPH+P
NO coincide con "PP" pero sí con "PHP" y "PHHP" y "PHHHHHHP" etcétera.
Comodín
El comodín es un punto .
y coincide con cualquier carácter. Así el patrón m.s
coincidirá con cualquier tres caracteres que empiecen con "m" y terminan con "s" como en la palabra "mas" o "mes" per anote que sólo coincida con esas letras aún si son parte de palabras más largas. Lo puede extender a un patrón como m.*s
lo cual coincidirá con todo que empiece con "m" y termina con "s" sin importar tamaño. Se coincide con tanto "mientras" como "mira a el árbol con tantas"
Rangos y conjuntos
Un conjunto se hace con corchetes []
. Se coincide con todo que contiene. Así el patrón [abc]
coincide con "a" y "b" y "c". También soporta un rango: [a-m]
que coincide con cualquiera letra entre "a" y "m" por lo cual se coincide con "a" y "b" y "c" hasta llegar a "l" y "m".
Y más...
Hay más maneras de coincidir, por supuesto. Manera como coincidir con espacias en blanco, palabras, dígitos. Hay maneras de negar y escapar. Y todo se puede usar junto para la coincidencia de patrones complicados.
preg_match y preg_match_all
Las funciones más usadas relacionadas con regex en PHP son preg_match
y preg_match_all
. Las usa de esta forma:
<?php
// preg_match($patrón, $sujeto, $coincidencias);
$patron = '/PHP/';
$sujeto = 'Verdadero PHP';
preg_match($patron, $sujeto, $coincidencias);
print_r($coincidencias);
/* Salida:
Array
(
[0] => PHP
)
*/
// preg_match sólo encuentra la primera coincidencia
// Anote que pasa al buscar por vocales
$patron = '/[aeiou]/';
$sujeto = 'José compró una vieja zampoña en Perú.';
preg_match($patron, $sujeto, $coincidencias);
print_r($coincidencias);
/* Salida:
Array
(
[0] => o
)
*/
// Ahora preg_match_all
// preg_match_all($patron, $sujeto, $coincidencias);
$patron = '/[aeiou]/';
$sujeto = 'José compró una vieja zampoña en Perú.';
preg_match_all($patron, $sujeto, $coincidencias);
print_r($coincidencias);
/* Salida:
Array
(
[0] => Array
(
[0] => o
[1] => o
[2] => u
[3] => a
[4] => i
[5] => e
[6] => a
[7] => a
[8] => o
[9] => a
[10] => e
[11] => e
)
)
*/
Anote de que no declaramos la variable $coincidencias
antes de que la usamos en la línea 5. Eso es porque la función preg_match
nos la declara. Esta técnica se llama "pasar por referencia." No es ideal, pero es una de las particularidades del idioma.
preg_match y preg_match_all si devuelven algo, pero no los resultados. Los resultados sólo vienen en el parámetro $coincidencias
. Los valores devueltos, según la documentación:
preg_match() devuelve 1 si
pattern
coincide con elsubject
dado, 0 si no, ofalse
si ocurrió un error.
Ejemplos
Regex es poderoso y rápido. Hay un sin fin de maneras en que un programador quisiera usarlo. A menudo se usa en validación de entrada del usuario.
Validación de email
Desde la creación de direcciones de email, las reglas en lo que se forma una dirección valida se ha cambiado. Al hacerse más complicada, la habilidad de checar una dirección de email es más difícil de determinar. Una búsqueda en línea quizá le dará patrones como:
^\w*(\-\w)?(\.\w*)?@\w*(-\w*)?\.\w{2,3}(\.\w{2,3})?$
^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$
^(?=[a-z][a-z0-9@._-]{5,40}$)[a-z0-9._-]{1,20}@(?:(?=[a-z0-9-]{1,15}\.)[a-z0-9]+(?:-[a-z0-9]+)*\.){1,2}[a-z]{2,6}$
Tal vez puede usar uno de estos. Si necesita una manera definitiva de checar, probablemente usaría el más elegante: filter_var($email, FILTER_VALIDATE_EMAIL)
per es bueno saber que puede validar a direcciones de email utilizando regex.
Validación de números de teléfono
Números de teléfono varían much por todo el mundo. Sin embargo, para un número de los E.E.U.U, alguno de estos sirven:
/(\+?(\b1)?[\ .\/-]?((?(2)|(\b))|(\())\d{3}(?(?<=\(\d{3})\)|)[\ .\/-]?)?(?(1)|\b)\d{3}[\ .\/-]?\d{4}[\ ]?([xX][\ ]?\d{1,5})?\b/gm
/^(\+?\d{0,2})?[\D]?\(?(\d{3})\)?[\D]?(\d{3})[\D]?(\d{4})$/gm
Códigos ZIP
Para códigos ZIP de los E.E.U.U.:
(^\d{5}$)
Recursos
- Wikipedia: Expresión regular
- Manual de PHP: Funciones de PCRE
- regex101
- Learn Regex: A Beginner’s Guide (inglés)
- Learn, build, and test regex (inglés)
Retos
Ejemplos de validación de regex
Trata de usar los ejemplos en PHP. Usa la preg_match
y la preg_match_all
funciones.
Patio de juegos de regex
Visita uno de los siguientes sitio relacionados al regex: regex101.com o regexr.com. Usa su interfaz para tratar y coincidir lo siguiente:
- Su nombre de entre una lista de nombres
- Las letras "P", "H", "p", y "h" de entre un párrafo al azar
- Cualquiera palabra que empiece con la letra "r" y termina con la letra "s"