Comunidad de diseño web y desarrollo en internet

Expresiones regulares en PHP

Las expresiones regulares son una serie de caracteres que forman un patrón, normalmente representativo de otro grupo de carácteres mayor, de tal forma que podemos comparar el patrón con otro conjunto de carácteres para ver las coincidencias.

Las expresiones regulares estan disponibles en casi cualquier lenguaje de programación, 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, aún sin saberlo, al menos en su vertiente mas básica. 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 patrón * coincide con cualquier cadena de caracteres.

Unos ejemplos simplificados:



    am // este es nuestro patrón. Si lo comparamos con:
    am // coincide
    panorama // coincide
    ambicion // coincide
    campamento // coincide
    mano // no coincide

Se trata sencillamente de ir cotejando un patrón (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 inglés).

Otro ejemplo:



    el //este es el patrón
    el ala aleve del leve abanico // si lo comparamos con esta cadena, si coincide

Hasta ahora los ejemplos han sido sencillos, ya que los patrones usados eran literales, es decir que sólo encontramos coincidencias cuando hay una ocurrencia exacta.

Si sabemos de antemano la cadena exacta a buscar, no es necesario quebrarse con un patrón complicado, podemos usar como patrón la exacta cadena que buscamos, y esa y no otra será la que de coincidencia. Así, si en una lista de nombres buscamos los datos del usuario pepe podemos usar pepe como patrón. Pero si además 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 más eficaz y rápidamente con literales.

Caracteres y Metacaracteres


Nuestro patrón puede estar formado por un conjunto de carácteres (un grupo de letras, números o signos) o por meta caracteres que representan otros carácteres, o permiten una búsqueda 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 utilización, agrupandolos segun su finalidad.

MetaCaracteres de posicionamiento, o anclas


Los signos ^ y $ sirven para indicar donde debe estar situado nuestro patrón dentro de la cadena para considerar que existe una coincidencia.

Cuando usamos el signo ^ queremos decir que el patrón debe aparecer al principio de la cadena de carácteres comparada. Cuando usamos el signo $ estamos indicando que el patrón debe aparecer al final del conjunto de carácteres. O mas exactamente, antes de un caracter de nueva línea. Así:

    ^am // nuestro patrón
    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


Escapando caracteres


Puede suceder que necesitemos incluir en nuestro patrón algun metacaracter como signo literal, es decir, por sí mismo y no por lo que representa. Para indicar esta finalidad usaremos un carácter de escape: la barra invertida \.
Así, un patrón definido como 12\$ no coincide con una cadena terminada en 12, y sí con 12$.

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 patrón representa cualquier caracter excepto nueva línea.

Y como acabamos de ver, si lo que queremos buscar en la cadena es precisamente un punto, deberemos escaparlo: \.

    patrón: '.l'
    el ala aleve del leve abanico


Observa en el ejemplo anterior como el patrón 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 patrón que puede estar una o más veces, o puede no estar ? Para esto usamos un tipo especial de meta carácteres: los multiplicadores.

Estos metacaracteres que se aplican al caracter o grupo de caracteres que les preceden, indican en que número 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
    // ab* coincide con "a", "ab", "abbb", etc.
    //ejemplo:
    cant*a // coincide con canta, cana, cantttta


  • ? // coincide si el carácter (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 carácter (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


Metacaracteres de rango


Los corchetes [] incluidos en un patrón permiten especificar el rango de caracteres válidos a comparar. Basta que exista cualquiera de ellos para que se de la condición:

  • [abc] // El patrón coincide con la cadena si en esta hay
    // cualquiera de estos tres carácteres: a, b, c

  • [a-c] // coincide si existe una letra en el rango ("a", "b" o "c")
    c[ao]sa // coincide con casa y con cosa

  • [^abc] // El patrón coincide con la cadena si en esta NO hay
    // ninguno de estos tres carácteres: a, b, c
    // Nota que el signo ^ aqui tiene un valor excluyente

  • c[^ao]sa // Coincide con cesa, cusa, cisa (etc); no coincide
    // con casa ni cosa

  • [0-9] // Coincide con una cadena que contenga cualquier
    // número entre el 0 y el 9

  • [^0-9] // Coincide con una cadena que NO contenga ningun
    // número

  • [A-Z] // Coincide con cualquier carácter alfabetico,
    // en mayúsculas. No incluye numeros.

  • [a-z] // Como el anterior, en minúsculas

  • [a-Z] // Cualquier carácter alfabético, mayusculas o minusculas

Una cuestión a recordar es que las reglas de sintaxis de las expresiones regulares no se aplican igual dentro de los corchetes. Por ejemplo, el metacarácter ^ 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 corchetes- caracteres normales.


    patrón: [aeiou]
    el ala aleve del leve abanico

    patrón: [^aeiou]
    el ala aleve del leve abanico

    patrón: [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 carácter 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 carácter
    // que no sea espacio en blanco

    // solo regex POSIX
    [[:alpha:]] // cualquier carácter alfabético aA - zZ.
    [[:digit:]] // Cualquier número (entero) 0 - 9
    [[:alnum:]] // Cualquier carácter alfanumérico aA zZ 0 9
    [[:space:]] // espacio


Metacaracteres de alternancia y agrupadores



    (xyz) // coincide con la secuencia exacta xyz
    x|y // coincide si esta presente x ó y

    (Don|Doña) // coincide si precede "Don" o "Doña"

Los paréntesis sirven no solamente para agrupar secuencias de caracteres, sino también 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 páginas siguientes.

Un ejemplo típico sería una expresion regular cuyo patrón capturase direcciones url válidas y con ellas generase links al vuelo:

Código :

<? 
$text = "una de las mejores páginas es http://www.cristalab.com";
$text = ereg_replace("http:\/\/(.*\.(com|net|org))","\1", $text);
print $text;
?> 


El anterior ejemplo produciría un enlace usable, donde la url se tomaría de la retro-referencia \0 y la parte visible de la retro-referencia \1 una de las mejores páginas es www.cristalab.com

Fijate que en el ejemplo anterior usamos dos grupos de paréntesis (anidados), por lo que se producirían dos capturas: La retro-referencia \0 coincide con la coincidencia buscada. Para capturarla no es preciso usar paréntesis.

La retro-referencia \1 coincide en este caso con "www.cristalab.com" y es capturada por el paréntesis (.*\.(com|net|org))

La retro-referencia \2 coincide con "net" y se corresponde con el paréntesis anidado (com|net|org)

Ten en cuenta que esta característica de capturar ocurrencias y tenerlas disponibles para retroreferencias consume recursos del sistema. Si quieres usar paréntesis 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 ?:

Código :

<?
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 retro-referencia, o hasta 200 (en total) si buscamos subpatrones sin capturarlos.

Este artículo es una copia de otro artículo original. El contenido de Cristalab es aportado por sus usuarios y tardamos en encontrar los plagios, los cuales NO aprobamos ni apoyamos. Si tienes la fuente original de este artículo, posteala en los comentarios

¿Sabes SQL? ¿No-SQL? Aprende MySQL, PostgreSQL, MongoDB, Redis y más con el Curso Profesional de Bases de Datos que empieza el martes, en vivo.

Publica tu comentario

o puedes...

¿Estás registrado en Cristalab y quieres
publicar tu URL y avatar?

¿No estás registrado aún pero quieres hacerlo antes de publicar tu comentario?

Registrate