Introducción a las expresiones regulares y primeros pasos para comprenderlas.
Las expresiones regulares son una serie de carácteres 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:
patrón: 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 patrón complicado, podemos usar como patrón 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 patrón. 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 patrón puede estar formado por un conjunto de carácteres (un grupo de letras, numeros 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.
Meta caracteres 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 linea Asi:
<?
^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
?>
o como en el ejemplo anterior:
patrón: ^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.
patrón: 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 patrón "el" no está situado al final.
Para mostrar una coincidencia en este ejemplo, tendriamos que buscar "co":
patrón: co$
con el ala aleve del leve abanico
Hemos comenzado por unos metacaracteres especiales, ya que ^ $ no representan otros carácteres, sino posiciones en una cadena. Por eso, se conocen tambien como anchors o anclas.
Escapando caracteres
Puede suceder que necesitemos incluir en nuestro patrón algun metacaracter como signo literal, es decir, por si 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$:
patrón: 100$
el ala aleve del leve abanico cuesta 100$
patrón: 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 número 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 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 mas 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 ?>
patrón: 'a*le'
el ala aleve del leve abanico
patrón: ' ?le'
el ala aleve del leve abanico
patrón: ' +le'
el ala aleve del leve abanico
Ademas de estos cuantificadores sencillos tambien podemos especificar el numero de veces máximo y mínimo que debe darse para que haya una ocurrencia:
patrón: (.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 máximo "y" veces
// "ab{2}" coincide con "abb": exactamente dos ocurrencias de "b"
// "ab{2,}" coincide con "abb", "abbbb" ... Como mínimo dos
// ocurrencias de b, máximo indefinido
// "ab{3,5}" coincide con "abbb", "abbbb", o "abbbbb": Como minimo
// dos ocurrencias, como máximo 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 máximo. NO
// puedes dejar el valor inicial vacío
a{5} // exactamente 5 letras "a"
?>
Por tanto, los cuantificadores * + ? pueden también 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)
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:
patrón: 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 patrón complicado, podemos usar como patrón 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 patrón. 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 patrón puede estar formado por un conjunto de carácteres (un grupo de letras, numeros 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.
Meta caracteres 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 linea Asi:
<?
^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
?>
o como en el ejemplo anterior:
patrón: ^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.
patrón: 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 patrón "el" no está situado al final.
Para mostrar una coincidencia en este ejemplo, tendriamos que buscar "co":
patrón: co$
con el ala aleve del leve abanico
Hemos comenzado por unos metacaracteres especiales, ya que ^ $ no representan otros carácteres, sino posiciones en una cadena. Por eso, se conocen tambien como anchors o anclas.
Escapando caracteres
Puede suceder que necesitemos incluir en nuestro patrón algun metacaracter como signo literal, es decir, por si 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$:
patrón: 100$
el ala aleve del leve abanico cuesta 100$
patrón: 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 número 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 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 mas 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 ?>
patrón: 'a*le'
el ala aleve del leve abanico
patrón: ' ?le'
el ala aleve del leve abanico
patrón: ' +le'
el ala aleve del leve abanico
Ademas de estos cuantificadores sencillos tambien podemos especificar el numero de veces máximo y mínimo que debe darse para que haya una ocurrencia:
patrón: (.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 máximo "y" veces
// "ab{2}" coincide con "abb": exactamente dos ocurrencias de "b"
// "ab{2,}" coincide con "abb", "abbbb" ... Como mínimo dos
// ocurrencias de b, máximo indefinido
// "ab{3,5}" coincide con "abbb", "abbbb", o "abbbbb": Como minimo
// dos ocurrencias, como máximo 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 máximo. NO
// puedes dejar el valor inicial vacío
a{5} // exactamente 5 letras "a"
?>
Por tanto, los cuantificadores * + ? pueden también 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)
Este artículo continúa en el manual de expresiones regulares.
irv.