Expresiones Regulares
Expresiones Regulares
Expresiones Regulares
com
Expresiones regulares
Autores del manual Este manual ha sido realizado por los siguientes colaboradores de DesarrolloWeb.com: irv.
http://www.ignside.net/ (6 captulos)
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
Expresiones regulares
Las expresiones regulares son una serie de carcteres que forman un patrn, normalmente representativo de otro grupo de carcteres mayor, de tal forma que podemos comparar el patrn con otro conjunto de carcteres para ver las coincidencias. Las expresiones regulares estan disponibles en casi cualquier lenguaje de programacin, pero aunque su sintaxis es relativamente uniforme, cada lenguaje usa su propio dialecto. Si es la primera vez que te acercas al concepto de expresiones regulares (regex para abreviar) te animar saber que seguro que ya las has usado, an sin saberlo, al menos en su vertiente mas bsica. Por ejemplo, cuando en una ventana DOS ejecutamos dir *.* para obtener un listado de todos los archivos de un directorio, estamos utilizando el concepto de expresiones regulares, donde el patrn * coincide con cualquier cadena de caracteres. Unos ejemplos simplificados:
<? am // este es nuestro patrn. Si lo comparamos con: am // coincide panorama // coincide ambicion // coincide campamento // coincide mano // no coincide ?>
Se trata sencillamente de ir cotejando un patrn (pattern) -que en este ejemplo es la secuencia de letras 'am'- con una cadena (subject) y ver si dentro de ella existe la misma secuencia. Si existe, decimos que hemos encontrado una coincidencia (match, en ingls). Otro ejemplo: patrn: el el ala aleve del leve abanico Hasta ahora los ejemplos han sido sencillos, ya que los patrones usados eran literales, es decir que solo encontramos coincidencias cuando hay una ocurrencia exacta. Si sabemos de antemano la cadena exacta a buscar, no es necesario quebrarse con un patrn complicado, podemos usar como patrn la exacta cadena que buscamos, y esa y no otra ser la que de coincidencia. Asi, si en una lista de nombres buscamos los datos del usuario pepe podemos usar pepe como patrn. Pero si ademas de pepe nos interesa encontrar ocurrencias de pepa y pepito los literales no son suficientes. El poder de las expresiones regulares radica precisamente en la flexibilidad de los patrones, que pueden ser confrontados con cualquier palabra o cadena de texto que tenga una estructura conocida. De hecho normalmente no es necesario usar funciones de expresiones regulares si vamos a usar patrones literales. Existen otras funciones (las funciones de cadena) que trabajan mas eficaz y rapidamente con literales. Caracteres y meta caracteres Nuestro patrn puede estar formado por un conjunto de carcteres (un grupo de letras,
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin. 2
numeros o signos) o por meta caracteres que representan otros carcteres, o permiten una bsqueda contextual. Los meta-caracteres reciben este nombre porque no se representan a ellos mismos, sino que son interpretados de una manera especial. He aqui la lista de meta caracteres mas usados: .*?+[](){}^$|\ Iremos viendo su utilizacin, agrupandolos segun su finalidad. Meta caracteres de posicionamiento, o anclas Los signos ^ y $ sirven para indicar donde debe estar situado nuestro patrn dentro de la cadena para considerar que existe una coincidencia. Cuando usamos el signo ^ queremos decir que el patrn debe aparecer al principio de la cadena de carcteres comparada. Cuando usamos el signo $ estamos indicando que el patrn debe aparecer al final del conjunto de carcteres. O mas exactamente, antes de un caracter de nueva linea Asi:
<? ^am // nuestro patrn am // coincide cama // no coincide ambidiestro // coincide Pam // no coincide caramba // no coincide am$ am // coincide salam // coincide ambar // no coincide Pam // coincide ^am$ am // coincide salam // no coincide ambar // no coincide ?>
o como en el ejemplo anterior: patrn: ^el el ala aleve del leve abanico Las expresiones regulares que usan anclas solo devolveran una ocurrencia, ya que por ejemplo, solo puede existir una secuencia el al comienzo de la cadena. patrn: el$ el ala aleve del leve abanico Y aqui no encontramos ninguna, ya que en la cadena a comparar (la linea en este caso) el patrn "el" no est situado al final. Para mostrar una coincidencia en este ejemplo, tendriamos que buscar "co":
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
patrn: co$ con el ala aleve del leve abanico Hemos comenzado por unos metacaracteres especiales, ya que ^ $ no representan otros carcteres, sino posiciones en una cadena. Por eso, se conocen tambien como anchors o anclas. Escapando caracteres Puede suceder que necesitemos incluir en nuestro patrn algun metacaracter como signo literal, es decir, por si mismo y no por lo que representa. Para indicar esta finalidad usaremos un carcter de escape, la barra invertida \. As, un patrn definido como 12\$ no coincide con una cadena terminada en 12, y s con 12$: patrn: 100$ el ala aleve del leve abanico cuesta 100$ patrn: 100\$ el ala aleve del leve abanico cuesta 100$ Fijate en los ejemplos anteriores. En el primero, no hay coincidencia, porque se interpreta "busca una secuencia consistente en el nmero 100 al final de la cadena", y la cadena no termina en 100, sino en 100$. Para especificar que buscamos la cadena 100$, debemos escapar el signo $ Como regla general, la barra invertida \ convierte en normales caracteres especiales, y hace especiales caracteres normales. El punto . como metacaracter Si un metacaracter es un caracter que puede representar a otros, entonces el punto es el metacaracter por excelencia. Un punto en el patrn representa cualquier caracter excepto nueva lnea. Y como acabamos de ver, si lo que queremos buscar en la cadena es precisamente un punto, deberemos escaparlo: \. patrn: '.l' el ala aleve del leve abanico Observa en el ejemplo anterior como el patrn es cualquier caracter (incluido el de espacio en blanco) seguido de una l. Metacaracteres cuantificadores Los metacaracteres que hemos visto ahora nos informan si nuestro patron coincide con la cadena a comparar. Pero y si queremos comparar con nuestra cadena un patrn que puede estar una o mas veces, o puede no estar ? Para esto usamos un tipo especial de meta carcteres: los multiplicadores. Estos metacaracteres que se aplican al caracter o grupo de caracteres que les preceden indican en que nmero deben encontrarse presentes en la cadena para que haya una ocurrencia. Por ello se llaman cuantificadores o multiplicadores. Los mas usados son * ? +
<? * // coincide si el caracter (o grupo de caracteres) que le // precede esta presente 0 o mas veces
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
// ab* coincide con "a", "ab", "abbb", etc. //ejemplo: cant*a // coincide con canta, cana, cantttta ? // coincide si el carcter (o grupo de caracteres) que precede // esta presente 0 o 1 vez // ab? coincide con "a", "ab", no coincide con "abb" // ejemplo: cant?a // coincide con canta y cana d?el // coincide con del y el (ala)?cena // coincide con cena y alacena + // coincide si el carcter (o grupo) que le precede est // presente al menos 1 o mas veces. // ab+ coincide con "ab", "abbb", etc. No coincide con "a" //ejemplo: cant+a // coincide con canta, canttttta, NO coincide con // cana ?>
patrn: 'a*le' el ala aleve del leve abanico patrn: ' ?le' el ala aleve del leve abanico patrn: ' +le' el ala aleve del leve abanico Ademas de estos cuantificadores sencillos tambien podemos especificar el numero de veces mximo y mnimo que debe darse para que haya una ocurrencia: patrn: (.a){2} el ala aleve del leve abanico
<? {x,y} // coincide si la letra (o grupo) que le precede esta presente // un minimo "x" veces y como mximo "y" veces // "ab{2}" coincide con "abb": exactamente dos ocurrencias de "b" // "ab{2,}" coincide con "abb", "abbbb" ... Como mnimo dos // ocurrencias de b, mximo indefinido // "ab{3,5}" coincide con "abbb", "abbbb", o "abbbbb": Como minimo // dos ocurrencias, como mximo 5 a{2,3} // coincide con casaa, casaaa a{2, } // coincide con cualquier palabra que tenga al // menos dos "a" o mas: casaa o casaaaaaa, no con casa a{0,3} // coincide con cualquier palabra que tenga 3 o // menos letras "a". // NOTA: puedes dejar sin especificar el valor mximo. NO // puedes dejar el valor inicial vaco a{5} // exactamente 5 letras "a" ?>
Por tanto, los cuantificadores * + ? pueden tambin ser expresados as: * equivale a {0,} (0 o mas veces) + equivale a {1,} (1 o mas veces) ? equivale a {0,1} (0 o 1 vez)
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
Una cuestin a recordar es que las reglas de sintaxis de las expresiones regulares no se aplican igual dentro de los corchetes. Por ejemplo, el metacarcter ^ no sirve aqui de ancla, sino de caracter negador. Tampoco es necesario escapar todos los metacaracteres con la barra invertida. Solo ser necesario escapar los siguientes metacaracteres: ] \ ^ El resto de metacaracteres pueden incluirse ya que son considerados -dentro de los corchetescaracteres normales. patrn: [aeiou] el ala aleve del leve abanico patrn: [^aeiou] el ala aleve del leve abanico
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
patrn: [a-d] el ala aleve del leve abanico Como estos patrones se usan una y otra vez, hay atajos:
<? // atajo equivale a significado \d [0-9] // numeros de 0 a 9 \D [^0-9] // el contrario de \d \w [0-9A-Za-z] // cualquier numero o letra \W [^0-9A-Za-z] // contrario de \w, un carcter que no // sea letra ni numero \s [ \t\n\r] // espacio en blanco: incluye espacio, // tabulador, nueva linea o retorno \S [^ \t\n\r] // contrario de \s, cualquier carcter // que no sea espacio en blanco // solo regex POSIX [[:alpha:]] // cualquier carcter alfabtico aA - zZ. [[:digit:]] // Cualquier nmero (entero) 0 - 9 [[:alnum:]] // Cualquier carcter alfanumrico aA zZ 0 9 [[:space:]] // espacio ?>
patrn: (al) el ala aleve del leve abanico patrn: a(l|b) el ala aleve del leve abanico Los parntesis sirven no solamente para agrupar secuencias de caracteres, sino tambin para capturar subpatrones que luego pueden ser devueltos al script (backreferences). Hablaremos mas de ello al tratar de las funciones POSIX y PCRE, en las paginas siguientes. Un ejemplo tpico sera una expresion regular cuyo patrn capturase direcciones url validas y con ellas generase links al vuelo:
<? $text = "una de las mejores pginas es http://www.blasten.com"; $text = ereg_replace("http:\/\/(.*\.(com|net|org))", "\1", $text); print $text; ?>
El anterior ejemplo producira un enlace usable, donde la url se tomara de la retro-referencia \ 0 y la parte visible de la retro-referencia \1 una de las mejores pginas es www.ignside.net
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
Fijate que en el ejemplo anterior usamos dos grupos de parentesis (anidados), por lo que se producirian dos capturas: La retro-referencia \0 coincide con la coincidencia buscada. Para capturarla no es preciso usar parentesis. La retro-referencia \1 coincide en este caso con "www.blasten.com" y es capturada por el parentesis (.*\.(com|net|org)) La retro-referencia \2 coincide con "net" y se corresponde con el parentesis anidado (com|net| org) Ten en cuenta que esta caracteristica de capturar ocurrencias y tenerlas disponibles para retroreferencias consume recursos del sistema. Si quieres usar parentesis en tus expresiones regulares, pero sabes de antemano que no vas a reusar las ocurrencias, y puedes prescindir de la captura, coloca despues del primer parentesis ?:
<? text = ereg_replace("http:\/\/(.*\.(?:com|net|org))", "<a href=\"\0\">\1</a>", $text); ?>
Al escribir (?:com|net|org) el subpatron entre parentesis sigue agrupado, pero la coincidencia ya no es capturada. Como nota final sobre el tema, PHP puede capturar hasta 99 subpatrones a efectos de retroreferencia, o hasta 200 (en total) si buscamos subpatrones sin capturarlos. Artculo por irv.
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
Y para comprobarlo en la prctica, usamos una de las funciones de php relacionadas con las expresiones regulares:ereg(). Acudiendo al manual php, podemos averiguar que esta funcin tiene la siguiente sintaxis: ereg (string pattern, string string) Busca en string las coincidencias con la expresin regular pattern. La bsqueda diferencia entre maysculas y minsculas. Devuelve un valor verdadero si se encontr alguna coincidencia, o falso in no se encontraron coincidencias u ocurri algn error. Podramos usar esta funcion para un validador email con algo asi como:
<? // establecemos una secuencia condicional: si la variable $op no existe y // es igual a "ds", se muestra un formulario if ($op != "ds") { ?> <form> <input type=hidden name="op" value="ds"> <strong>Tu email:</strong><br /> <input type=text name="email" value="" size="25" /> <input type=submit name="submit" value="Enviar" /> </form> <? } // Si $op existe y es igual a "ds"m, se ejecuta la funcin ereg buscando // nuestra cadena dentro del patrn $email que es la direccion enviada por // el usuario desde el formulario anterior else if ($op == "ds") { if (ereg("^[^@ ]+@[^@ ]+.[^@ .]+$", $email ) ) { print "<BR>Esta direccin es correcta: $email"; } else {echo "$email no es una direccin valida";} } ?>
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
No hace falta advertir que se trata de un ejemplo muy elemental, que dar por vlida cualquier direccin email que tenga una mnima apariencia de normalidad (por ejemplo, daria por valida 'midireccionnn@noteimporta.commm') Artculo por irv.
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
10
ereg_replace: Busca cualquier ocurrencia del patrn en la cadena y la reemplaza por otra. eregi_replace: como la anterior pero sin distinguir mayusculas minusculas: patrn, reemplazo, cadena a confrontar
<? $cadena = ereg_replace ("^am", "hispano-am", "america"); // $cadena = hispano-america ?>
split() divide una cadena en piezas (que pasan a un array) usando expresiones regulares: spliti: como el anterior, sin diferenciar Mayusculas-minusculas Es bsicamente igual que explode, pero utilizando expresiones regulares para dividir la cadena, en lugar de expresiones literales
<? $date = "24-09-2003"; list($month, $day, $year) = split ('[/.-]', $date); ?>
Almacenando los resultados con ereg Podemos pasar un patrn con subpatrones agrupados en parentesis. Si en este caso usamos ereg, podemos aadir un tercer parmetro: el nombre de un array que almacenar las ocurrencias; $array[1] contendr la subcadena que empieza en el primer parntesis izquierdo; $array[2] la que comienza en el segundo, etc. $array[0] contendr una copia de la cadena.
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
11
<? $date = "24-09-2003"; // pasamos una fecha formato dd-mm-yyyy if (ereg ("([0-9]{1,2})-([0-9]{1,2})-([0-9]{4})", $date, $mi_array)) { echo "$mi_array[3].$mi_array[2].$mi_array[1]"; // coincide. Lo mostramos en orden inverso porque somos asi : ) } else { echo "Invalid date format: $date"; // no coincide } ?>
Almacenando los resultados con ereg_replace: backreferences De forma muy similar a ereg, las funciones de bsqueda y sustitucin ereg_replace y eregi_replace pueden almacenar y reutilizar subocurrencias (subpatrones encontrados en la cadena). La principal diferencia es la forma de llamar las subocurrencias almacenadas, ya que necesitamos utilizar la barra invertida: \\0, \\1, \\2, y asi hasta un mximo de 9. La primera referencia \\0 hace referencia a la coincidencia del patrn entero; el resto, a las sub-ocurrencias de los sub-patrones, de izquierda a derecha. Por ejemplo vamos a usar esta capacidad para convertir una cadena que muestra una url en un enlace:
<? $url = "la pgina blasten.com (http://www.blasten.com)"; $url = ereg_replace ("(http|ftp)://(www\.)?(.+)\.(com|net|org)","<a href=\"\\0 \">\\3</a>",$url); echo $url; ?>
Funciones PCRE
Las funciones PCRE son "perl-compatibles". Perl es uno de los lenguajes de programacin con mejor motor de expresiones regulares, y adems es muy conocido. Esta librera es utilizada (con distintas variantes) no solo por Perl, sino por el propio PHP y tambien en otros entornos, como el server Apache, Phyton o KDE. Las funciones de expresiones regulares PCRE de PHP son mas flexibles, potentes y rpidas que las POSIX. Prcticamente no existe ninguna diferencia sintctica entre un patrn PCRE o POSIX; muchas veces son intercambiables. Naturalmente existe alguna diferencia. La mas evidente, que nuestro patrn deber estar marcado en su principio y final unos delimitadores, normalmente dos barras: /patron/ Delimitadores
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
12
Se puede usar como delimitador cualquier carcter especial (no alfanumerico) salvo la barra invertida \. La costumbre mas extendida es, como hemos visto, usar la barra /, sin embargo, si posteriormente vamos a necesitar incluir el mismo caracter delimitador en el patrn, tendremos que escaparlo, por lo que tiene sentido usar en esos casos unos delimitadores distintos: (), {}, [], o < > Modificadores Se colocan despues del patrn:
<? m // multilnea. Si nuestra cadena contiene varias lineas fsicas (\n) // respeta esos saltos de lnea, lo que significa, por ejemplo, // que las anclas ^ $ no se aplican al principio y final de la // cadena, sino al principio y final de cada linea s // El metacaracter . representa cualquier carcter menos el de // nueva linea. Con el modificador "s" tambien representa la nueva linea. i // Se confronta el patrn con la cadena ignorando Mayusculas minusculas x // ignora espacios (salvo que esten escapados o incluidos // especficamente dentro del rango de bsqueda. Ignora cualquier caracter // despues de almohadilla (#) hasta nueva lnea. Sirve para incluir // comentarios y hacer mas legible el patrn. e // solo en preg_replace. Evalua las ocurrencias como cdigo php antes // de realizar la sustitucin. A // El patrn es forzado a ser "anclado", esto es, solo existir una // ocurrencia si es al inicio de la cadena. E // el carcter $ en el patrn casar con el fin de la cadena. // Sin este modificador, $ casa tambien con el carcter inmediatamente // antes del de una nueva lnea. U // Este modificador invierte la "codicia" de los cuantificadores. // Si aplicamos U, * se convierte en perezoso (lazy) y *? vuelve a su // comportamiento normal. // Un cuantificador es "codicioso" (greedy) cuando intenta capturar todas // las ocurrencias posibles, y perezoso (lazy) cuando captura la // ocurrencia mas corta. ?>
Delimitadores de palabra En las funciones PCRE puedes usar \b que indica el comienzo y fin de una palabra (o mejor, de una secuencia alfanumerica): /\bpatron\b/ \B, por el contrario, se refiere a un patrn que no est al comienzo o fin de una palabra. Codicioso o no Las expresiones regulares que usan cuantificadores tienden a ser todo lo codiciosas que les sea permitido, siempre que respeten el patrn a seguir. Con el modificador U se invierte este comportamiento.
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
13
En modo codicioso el patrn casar todas las ocurrencias que pueda, mientras que en modo lazy o ungreedy, casar solo la mas corta posible (e). Advierte que las dos soluciones son correctas. patrn: /http:\/\/.*\.(com|net|org)/esto es un link: http://www.abc.com y este otro mas: http://www.blah.com patrn: /http:\/\/.*\.(com|net|org)/Uesto es un link: http://www.abc.com y este otro mas: http://www.blah.com Las funciones Tenemos cinco funciones PCRE: preg_match() preg_match_all() preg_replace() preg_split() preg_grep() preg_match busca el patrn dentro de la cadena, devolviendo TRUE si es hallado: patron, cadena [,array de resultados] Si indicamos el tercer parmetro, tendremos los resultados en un array; $array[0] contendr la ocurrencia del patrn; $array[1] tendr la cadena que case con el primer subpatrn y as sucesivamente. preg_match_all encuentra todas las ocurrencias del patrn en la cadena. patron, cadena, array de patrones, orden Si proporcionamos el cuarto parmetro, colocara las ocurrencias en un array siguiendo el orden indicado. preg_replace busca y reemplaza el patrn en la cadena. Tanto el patrn como la sustitucin pueden pasarse en array, y pueden contener expresiones regulares. Puede tambien especificarse un lmite mximo de ocurrencias. preg_split opera como split aunque tambien puedes pasarle expresiones regulares preg_grep busca el patrn dentro de un array, y devuelve otro array con las ocurrencias. patron, array El autor de este artculo ha creado una herramienta para probar expresiones regulares, que seguro nos ser de utilidad para comprobar nuestros conocimientos. Artculo por irv.
Expresiones regulares: www.desarrolloweb.com/manuales/expresiones-regulares.html Los manuales de DesarrolloWeb.com tienen el copyright de sus autores. No reproducir sin autorizacin.
14