Introducción a las Expresiones Regulares
Este manual
sólo pretende ser una pequeña guía
introductoria a las expresiones regulares, empezando por lo
básico para hacer expresiones sencillas o adaptar otras
a nuestras necesidades.
Por supuesto, puede contener errores o cosas
que se podrían mejorar. Para cualquier sugerencia,
cuestión o duda podeis contactar conmigo
en .
Espero que a alguien le resulte
útil.
- ¿Qué son las
expresiones regulares? - Algunos tipos de expresiones
regulares - Cómo podemos
usarlas - Empecemos: las unidades
"átomo" - El carácter
comodín - "Escapar"
caracteres - Otros caracteres
especiales - Repetición de átomos
avanzada - Grupos de caracteres.
Rangos. - Reemplazos
avanzados - Combinaciones
- Notas al utilizar
grep - Conclusiones
Colores:
En el manual las expresiones
regulares se representarán con letra Courier y
color
marrón:
expresión regular
Lo que esté en Courier pero sin estar en
marrón pueden ser cadenas o algo "literal".
1. ¿Qué son
las expresiones regulares?
Antes de empezar a hablar de ellas
mejor dejar claro al principio qué son :-D.
A veces necesitamos encontrar algo concreto en un
texto o
cadena, o reemplazar algo por otra cosa; ya sea en una
aplicación, o en un lenguaje de
programación. Por ejemplo si queremos buscar "tag" y
reemplazarlo por "etiqueta" la mayoría de aplicaciones o
lenguajes tienen una función
para hacerlo de forma sencilla.
Pero a veces lo que queremos hacer es más
complejo, porque puede que en vez de ser una palabra o parte de
palabra simple, necesitemos hacer algo como "búscame todas
las palabras que acaben en 'f' y que empiecen por un
número del 2 al 71" (por ejemplo) o "reemplaza las
palabras que contengan este grupo de
letras por esto".
En estos casos podemos utilizar las expresiones
regulares (que se pueden llamar regex o
regexp de forma abreviada), que es como un lenguaje para
poder definir
exactamente qué es lo que queremos buscar o
reemplazar.
2. Algunos tipos de
expresiones regulares
Hemos dicho antes que las expresiones regulares son como
un lenguaje para definir lo que queremos buscar de forma exacta,
pero este lenguaje no siempre es el mismo, quiero decir, hay
varios "tipos" de lenguajes.
Los que más se suelen utilizar son
dos:
- Expresiones regulares POSIX extendido
- Expresiones regulares de Perl
Aunque son muy parecidas no son exactamente iguales. En
este manual veremos generalmente el primer tipo (Expresiones
regulares POSIX) ya que son más fáciles para
empezar.
Las expresiones del segundo tipo hay que "encerrarlas"
entre unos caracteres especiales, normalmente se utiliza la barra
inclinada /. Con las expresiones POSIX (las que veremos
aquí) no hace falta.
Por ejemplo, para saber si un texto contiene "foo" se
haría así en las dos expresiones:
POSIX ==> foo
Perl ==> /foo/
Sí, "foo" también es una expresión
regular aunque evidentemente es el tipo más sencillo que
podemos hacer 🙂
A partir de ahora en esta guía hablaremos
principalmente de las expresiones regulares
POSIX, aunque la mayoría también se
harán de igual manera en Perl pero encerrandolas entre
caracteres (entre barras por ejemplo).
Cuando una expresión regular "encaja" con una
cadena, línea o lo que sea se dice que coincide,
o match en inglés.
Para poder utilizar las expresiones regulares
necesitamos "algo" que nos permita usarlas (sea una
aplicación o lenguaje de programación).
En entornos UNIX hay
muchas utilidades que nos permiten usarlas. Es el caso de 'GNU
Grep' o 'sed'.
Para utilizar las expresiones POSIX extendido con "grep"
hay que pasarle el parámetro "E" seguido de la
expresión regular.
Por ejemplo:
$ ls | grep -E <expresión>
Lo que haría sería devolvernos los nombres
de archivos del
directorio actual que coincidieran con la expresión
<expresión> (sin los > y < ).
En lenguajes de programación: como
ejemplo veremos cómo utilizarlas en PHP,
ya que es un lenguaje que nos permite usar los dos tipos de
expresiones regulares y además es un lenguaje bastante
utilizado y no hace falta compilar.
Si no te interesa cómo utilizarlas en PHP puedes
y
empezar con las expresiones regulares :-).
La función más básica para usar una
expresión regular POSIX en PHP es
ereg.
$resultado =
ereg("<expresión>",$cadena);
Nos devolverá TRUE si <expresión> ha
coincidido en $cadena o FALSE si no lo ha hecho.
También podemos utilizar eregi,
que hace lo mismo que ereg pero no distingue
entre mayúsculas y minúsculas.
Para reemplazar en PHP tenemos
ereg_replace (o su variante
eregi_replace ).
$cadena =
ereg_replace("<expresión>","<reemplazo>",$cadena);
Ese ejemplo aplicará la sustitución de
<expresión> por <reemplazo> a $cadena. Cuando
más adelante veamos el apartado de sustituciones veremos
que en <reemplazo> también podemos incluír
grupos que
coincidieron en <reemplazo>.
También hay más funciones que
permiten utilizar expresiones regulares pero como esto no es un
manual de PHP sólo veremos lo básico.
4. Empezamos: las unidades "átomo"
En expresiones regulares la "unidad" se llama
"átomo" y generalmente cada letra es un átomo. Por
ejemplo en la expresión regular
baz
cada letra es una unidad "átomo".
Sin embargo, a veces queremos que un átomo sea
más grande. Por ejemplo, más adelante veremos
modificadores que permiten coincidir la expresión si el
átomo se repite N veces. Si queremos que lo que se pueda
repetir sea un grupo de letras, podemos hacer que éstas
formen un átomo poniéndolas entre
paréntesis:
foo(bar)baz
Aquí las letras de "baz" seguirían siendo
átomos sueltos pero el grupo "bar" sería un
átomo todo entero.
Aparte los paréntesis tienen más
utilidades que veremos más adelante.
5. El carácter comodín
Un caso muy típico en expresiones regulares es
que a veces no sabemos exactamente qué letra queremos
buscar por ejemplo en medio de una palabra, pero queremos
utilizar un "comodín", o sea, cualquier letra.
En expresiones regulares POSIX el caracter
"comodín" es el punto (.).
Veamos un ejemplo: la expresión
regular
l.ca
coincidiría tanto con
laca
como con
loca
Como podemos ver el. representa cualquier
carácter.
Como hemos visto en los capítulos 4 y 5 en las
expresiones regulares existen caracteres especiales que hacen una
función (agrupar, comodines, etc.).
Pero ¿y si queremos representar el propio
carácter en vez de su función?
Quiero decir, en el capítulo anterior
veíamos esta expresión:
l.ca
Donde el "." coincidía con cualquier
carácter (incluido el propio punto, claro).
Pero ¿y si queremos que el "." no tenga esa
función, o sea, que la expresión sólo
coindica si encuentra de verdad l.ca no laca ni loca ni leca
?.
A esto se le llama "escapar" y se hace con la barra
invertida ( ). Así, para este ejemplo quedaría
así:
l.ca
Con lo cual ya sólo coincidiría con
"l.ca".
También podemos escapar la doble
barra:
\
🙂
7. Otros caracteres
especiales
El carácter circunflejo (^).
Coincide con el principio de una línea.
Por ejemplo, si queremos hacer coincidir las
líneas que empiecen por http de una
cadena, podríamos usar la expresión:
^http
Con lo cual sólo si el http está a
principio de línea coincidiría la expresión,
si http está en el medio o final no.
En ese sentido, coincidiría con
"http://www.google.com" pero
no con "El protocolo http es
el que..:".
El dólar ($): Coincide con el
final de una línea (al contrario que la
anterior).
Por ejemplo, si queremos hacer coincidir las
líneas que acaben por com de una cadena,
podríamos usar la expresión:
com$
Con lo cual sólo si el com está a final de
línea coincidiría la expresión, si com
está en el medio o final no.
En ese sentido, coincidiría con "www.google.com"
pero no con "www.google.com.ar".
Puede o no puede aparecer: El carácter
"interrogante" (?): Si colocamos un interrogante
después de un átomo, estamos indicando que el
átomo puede o no puede aparecer, la expresión
coincidirá en los dos casos. Ejemplo:
foo(baz)?bar
Que coincidiría con "foobazbar", y con "foobar".
Pero no con "foobazbazbar".
Repetición de átomos: El
carácter asterisco (*): Si colocamos un asterisco
después de un átomo estamos indicando que ese
átomo se repite cero o más veces,
o sea, que puede que no aparezca el átomo, que aparezca
una vez o que lo haga las veces que sean; con el asterísco
coincidirá siempre. Ejemplo:
go*gle
Que coincidiría con "gogle", "google",
"goooooogle", "gooooooooooooooooogle", pero también con
"ggle".
Otro ejemplo:
foo(bar)*baz
Que coincidiría con "foobarbaz", "foobarbarbaz",
"foobarbarbarbarbarbaz", "foobaz", pero no con "foobarrrrrrrbaz"
ni con "foobar".
Repetición de átomos: El
carácter "más" (+): Se comporta de forma
parecida al anterior, pero éste, al colocarlo
después de un átomo estamos indicando que el
átomo se repite al menos alguna vez.
Ejemplo:
go+gle
Que coincidiría con "gogle", "google",
"goooooogle", "gooooooooooooooooogle", pero no
con "ggle".
Otro ejemplo:
foo(bar)+baz
Que coincidiría con "foobarbaz", "foobarbarbaz",
"foobarbarbarbarbarbaz", pero no con "foobaz",
con "foobarrrrrrrbaz" ni con "foobar".
El carácter (|): Equivale a
"ó". Por ejemplo foobar|foobaz coincidiría tanto
con "foobar" como con "foobaz".
8. Repetición de
átomos avanzada
En el capítulo anterior hemos visto cómo
podemos indicar que un átomo podía repetirse. Pero
no teníamos mucho control sobre la
repetición ya que utilizando esos caracteres, ésta
siempre era infinita.
Utilizando los corchetes después
del átomo podemos indicar qué tipo de
repetición con más exactitud.
"Se repite N veces". Si dentro de los
corchetes ponemos un número, estamos indicando que el
átomo al que hacen referencia los corchetes se repite ese
número de veces.
Ejemplo:
go{4}gle
Coincidirá con "goooogle" pero no con "gogle",
con "google" ni con "ggle".
"Se repite de N a M veces". Si dentro
de los corchetes ponemos dos números separados por comas,
estamos indicando que el átomo al que hacen referencia los
corchetes se repite las veces que sea del primer
número al segundo.
Ejemplo:
go{4,8}gle
Coincidirá con "goooogle", "gooooogle",
"goooooogle", "goooooooogle" pero no con "gooogle", con "google"
ni con "ggle".
También si el segundo número no es nada (
por ejemplo {4,} ) quiere decir del primer número
al infinito.
9. Grupos de caracteres.
Rangos.
A veces en una expresión regular queremos que
coincida con una letra cualquiera dentro de un grupo de
letras.
Los grupos de caracteres se colocan entre "corchetes
planos" [ y ], y no hace falta
separarlos.
Por ejemplo:
s[ae]ca
Coincidiría tanto como con "seca" como con "saca"
pero no con "saeca" ni con "seaca".
Dentro de un grupo de caracteres pueden haber los que
hagan falta.
Dentro de un grupo de caracteres si ponemos el
carácter ^ al principio, el significado del grupo es al
revés: coincide con cualquier carácter que
no esté en el grupo.
Por ejemplo:
s[^iou]ca
Coincidiría tanto como con "seca" como con "saca"
pero no con "soca" ni con "suca" ni con "sica".
Rangos
Dentro de un grupo de caracteres también podemos
especificar rangos: de tal carácter a tal carácter,
o sea, cualquier carácter que esté
comprendido entre A y B. Tenemos en cuenta que si es una
letra el orden es el alfabético (abcdefg…) y si es un
número, orden numérico (123456…).
Ejemplo:
[0-9] y [0-9]
Que coincidirá con "2 y 8", "9 y 7", "2 y 0"…
pero no con "24 y 36" (si queremos que lo haga tendríamos
que aplicar algo de lo que hemos aprendido: ([0-9])+ y ([0-9])+
).
También pueden estar rangos y caracteres sueltos
en un mismo grupo.
Ejemplo:
f[^w-z0-9a]o
Que coincidiría con "foo", "feo", "fso" pero no
con "fwo", "fyo", "fzo", "f2o" ni "fao".
Dentro de una expresión regular, a la hora de
reemplazar podemos hacer referencia a algo que depende de lo que
contenga un grupo que hemos definido antes, en la
expresión.
Los grupos de paréntesis avanzados nos permiten
definir zonas ( entre ( y ) ).
El contenido (variable según lo que definamos dentro)
podemos referenciarlo en lo que vamos a reemplazar, utilizando la
barra invertida y un número del 0 al 9 según la
posición del grupo dentro de la expresión.
Ejemplo:
Buscar (([0-9])+) al cubo y reemplazar por 1 por si
mismo tres veces
En ese mismo ejemplo, el 1 haría referencia al
primer paréntesis.
Al aplicarlo a "48 al cubo" nos lo convertiría en
"48 por si mismo tres veces".
Notad que hemos puesto dos paréntesis porque el
primero sólo haría referencia al último
número (ya que [0-9] es sólo un número del 0
al 9…)
En PHP el ejemplo anterior podría ser
así:
<?php
$cadena = "474 al cubo";
$reemplazada = ereg_replace('(([0-9])+) al cubo','1 por
si mismo tres veces',$cadena);
print $reemplazada;
?>
Como obtenemos más potencia en una
expresión regular es combinando técnicas.
Por ejemplo, hemos visto cómo repetir
átomos. Si lo que queremos es hacer coincidir una zona
donde pueda ir "cualquier cosa" podemos utilizar el átomo
".". Por ejemplo:
{(.+)}
Coincidiría con cualquier cosa que estuviera
entre corchetes. Por ejemplo con "{Foo}". Además a la hora
de reemplazar podríamos utilizar 1 para referirnos a lo
que hay dentro del paréntesis como hemos visto
antes…
Con 'grep', como vimos antes podemos utilizar
expresiones regulares perfectamente.
Sólo hay que tener en cuenta una cosa: algunos
caracteres como los paréntesis o la misma barra invertida,
el intérprete "bash" intentará interpretarlos antes
de pasárselo a 'grep'. Por lo tanto debemos escaparlo con
(el dólar sería $, los paréntesis (, la
barra invertida \…)
Por ejemplo, para que nos devuelva las líneas de
"archivo.txt"
que contengan números:
$ cat archivo.txt | grep -E ([0-9])+
Recuerda que con "grep", dominando las expresiones
regulares, puedes hacer de todo, es una utilidad
potentísima 🙂
Y sobre todo utilizando las "pipes" (|) de UNIX que
redirigen la salida de otro comando al siguiente…
🙂
Por ejemplo, para enviar un correo a
prueba[arroba]yahoo.com conteniendo los archivos de /ejemplo que
sean.tar.gz o.tgz :
$ ls /ejemplo | grep -E \.tar\.gz$|\.tgz$ | mail
prueba[arroba]yahoo.com
😀
Espero que te haya sido útil el manual :-). Y eso
no es todo, en este manual hemos visto las expresiones
regulares POSIX extendido pero una vez que domines
éstas también puedes aprender las de
Perl, que son parecidas pero aparte son mucho
más potentes, ya que tienen modificadores que hacen de
todo 🙂
Eso sí, como son algo más liosas te
recomiendo dominar antes bien las POSIX 🙂
Este manual se distribuye bajo licencia Free
Distribution License (FDL), por supuesto puedes copiar,
redifundir o
redistribuirlo.
(C)opyLeft 2004,
Toad