Está en la página 1de 22

Basilio Carrero Nevado | Teora de Autmatas y Computacin | 16 de abril

de 2014

Abstract: This document is an introductory tutorial to using regular
expressions in Python with the re module based on A.M. Kuchlings Regular
Expression HOWTO. It provides a gentler introduction than the corresponding
section in the Library Reference.
PGINA 1
CONTENIDO
Introduccin ...................................................................................................... 2
Lo Bsico .......................................................................................................... 2
Caracteres Coincidentes ...................................................................................... 2
Notacin de cadenas en crudo ............................................................................... 3
Repeticiones..................................................................................................... 4
Usando expresiones regulares ............................................................................... 5
Compilacin de expresiones regulares ..................................................................... 5
Encajando Patrones ............................................................................................ 6
Funciones del mdulo ......................................................................................... 9
Funciones de cadenas ......................................................................................... 9
Patrones Avanzados ........................................................................................... 10
Ms Meta-caracteres ......................................................................................... 10
Agrupamiento ................................................................................................. 12
Grupos etiquetados y grupos no-capturados ............................................................ 14
Aserciones de bsqueda hacia delante ................................................................... 16
Modificando cadenas .......................................................................................... 17
Partiendo cadenas............................................................................................ 18
Bsqueda y reemplazo....................................................................................... 19
Recursos y herramientas de desarrollo y depuracin.................................................. 21
Online .......................................................................................................... 21
Off-line ......................................................................................................... 21
Referencias ...................................................................................................... 21




PGINA 2
INTRODUCCIN
El mdulo re provee de soporte para el uso de expresiones regulares al estilo Perl desde la versin
1.5, versiones anteriores de Python utilizan el mdulo regex que proporciona patrones al estilo
Emacs. Este ltimo fue eliminado completamente a partir de la versin 2.5.
Las expresiones regulares constituyen un pequeo lenguaje de propsito especfico empotrado en
Python y disponible a travs del mdulo re. Usando dicho lenguaje podemos especificar reglas
que encajarn contra un posible conjunto de cadenas de texto. Se pueden usar para comprobar si
una cadena sigue un patrn determinado o si existe coincidencia en algn punto de la misma,
tambin es posible trocearlas o sustituir ocurrencias que encajen en el patrn.
Los patrones son compilados a una serie de bytecodes que son ejecutados por el motor de
emparejamiento escrito en C a fin de verificar las posibles coincidencias.
El lenguaje de las expresiones regulares es relativamente pequeo y restringido, por lo que no
todas las tareas pueden realizarse de esta forma, incluso en ocasiones pueden aadir complejidad
innecesaria al problema. En estos casos es preferible usar cdigo Python que resulte en una mayor
claridad en detrimento de la velocidad de ejecucin.
LO BSICO
CARACTERES COINCIDENTES
La mayora de los caracteres coinciden por s mismos con su literal correspondiente. Por ejemplo:
texto coincide con la cadena texto.
Por otro lado tenemos los Meta-caracteres, que son caracteres especiales que afectan a la RE
alterando su significado. Esta es la lista completa que veremos a lo largo del documento:
. ^ $ * + ? { } [ ] \ | ( )
La pareja de corchetes nos permite especificar la clase a la que pertenece un carcter, esto es el
conjunto de caracteres en el que puede darse la coincidencia. Por ejemplo [abc] coincide con
los caracteres a, b o c. Tambin es posible emplear rangos, separando el carcter inicial
del final mediante -, quedando [a-c].
Los Meta-caracteres no estn activos dentro de una clase, son interpretados como literales,
perdiendo su significado especial. [akm$] coincide con a, k, m, o $.
Tambin es posible coincidir con los caracteres que no se listan complementando el conjunto,
esto se indica incluyendo ^ como primer carcter de la clase. Por ejemplo [^5] coincide con
cualquier carcter excepto 5.
PGINA 3
El Meta-caracteres ms importante es la barra invertida: \. Al igual que en las cadenas en
Python, la barra invertida puede ir seguida de otros caracteres para expresar secuencias con un
significado especial. Adems, es usado para escapar cualquier otro Meta-carcter cuando no
queremos que corresponda con ningn patrn. Por ejemplo, si queremos coincidir con [ o \,
debemos precederlos con la barra invertida: \[ o \\.
Algunas de las secuencias que comienzan con \ son conjuntos predefinidos de caracteres que se
emplean habitualmente como el conjunto de los nmeros, el conjunto de las letras o cualquier
cosa que no sea un carcter blanco. A continuacin se presentan en la siguiente tabla algunas de
las secuencias ms comunes junto a sus clases equivalentes. Para obtener una lista completa de
secuencias y sus definiciones de clase para cadenas Unicode, vea la ltima parte de la seccin
Regular Expression Syntax en la documentacin oficial de Python.
Secuencia Descripcin Clase equivalente
\d Cualquier dgito decimal [0-9]
\D Cualquier carcter no numrico [^0-9]
\s Cualquier carcter blanco [ \t\n\r\f\v]
\S Cualquier carcter no blanco [^ \t\n\r\f\v]
\w Cualquier carcter alfanumrico [a-zA-Z0-9_]
\W Cualquier carcter no alfanumrico [^a-zA-Z0-9_]
Las secuencias pueden incluirse en la definicin de una clase. Por ejemplo [\s,.] concuerda con
cualquier carcter blanco, , o .
Finalmente en esta seccin, el Meta-carcter . encaja con cualquier carcter excepto el de
nueva lnea (incluso es posible hacerlo coincidir tambin con este mediante la bandera de
compilacin re.DOTALL como veremos ms adelante).
NOTACIN DE CADENAS EN CRUDO
Como sealamos anteriormente, para escapar un Meta-carcter en una RE hemos de anteponer la
barra invertida, no obstante esto entra en conflicto con la representacin en Python de las cadenas
de literales, desde que se utiliza el mismo carcter para la misma funcin.
Pongamos por ejemplo que estamos tratando un fichero LaTeX y deseamos escribir una RE que
encaje con la cadena \section. La RE que deberamos compilar sera \\section, a su vez,
para representar dicha RE como una cadena de literales tenemos que volver a escapar cada barra
invertida, resultando en \\\\section.
PGINA 4
Esto puede complicar la lectura y dificultar la compresin de nuestras RE. La solucin pasa por
usar la notacin en crudo de cadenas, que es un modo de representar cadenas anteponiendo el
prefijo r, en el que la barra invertida no tiene significado especial y por tanto no necesitamos
escaparla por segunda vez. La siguiente tabla ilustra la diferencia entre la notacin regular y la
notacin en crudo:
Notacin Regular Notacin en Crudo
"ab*" r"ab*"
"\\\\section" r"\\section"
"\\w+\\s+\\1" r"\w+\s+\1"
REPETICIONES
A continuacin veremos cmo establecer que una porcin de la RE se repita un cierto nmero de
veces.
El primer Meta-carcter que nos brinda esta capacidad es *, que especifica que el carcter
precedente puede aparecer cero o ms veces en lugar de una sola vez. Por ejemplo: ga*to
coincidir con gto (0 caracteres a), gato (1 a), gaaato (3 a).
El motor interno presenta algunas limitaciones derivadas del tamao de un entero en C que
impiden coincidir ms de dos mil millones de veces, pero probablemente no tendrs memoria
suficiente para representar una cadena tan larga, por lo que no deberas preocuparte por este
lmite.
Otro Meta-carcter repetidor es +, que requiere que el carcter precedente aparezca al menos
una vez.
Tambin est ?, que especifica que el carcter puede aparecer una o ninguna veces, se puede
entender como opcional el carcter al que se aplica.
Por ltimo tenemos el ms complejo {m,n}, dnde m y n son enteros positivos, m es mnimo y
n el mximo nmero de ocurrencias del carcter que cuantifica. Es posible omitir uno de los dos,
en caso de omitir m se toma como mnimo 0, por el contrario si es n el que se omite se toma como
mximo infinito.
Ntese que {0,} es lo mismo que *, {1,} es equivalente a + y {0,1} es igual a ?, no
obstante se prefiere el uso de los segundos debido a que son ms cortos y fciles de leer.
Cabe destacar que las repeticiones anteriores son voraces, esto significa que el motor de
emparejamiento intentar consumir tantas repeticiones como le sea posible antes de pasar a la
siguiente porcin de la RE, si la porcin de la RE siguiente al carcter repetido no coincide, volver
hacia atrs y lo comprobar de nuevo con menos repeticiones.
PGINA 5
Se debe tener esto en cuenta cuando queremos construir expresiones que encajen en una cadena
que presente delimitadores balanceados, como por ejemplo los corchetes angulares que encierran
una etiqueta HTML.
Supongamos que tenemos la siguiente cadena: <html><head><title>Title</title>. Si
queremos capturar una sola etiqueta la RE <.*> no nos servira, ya que < coincidira; pero .*
consumira el resto de la cadena y al volver hacia atrs la coincidencia se dara con el ltimo
corchete de la cadena.
Es en este tipo de situaciones dnde se hace necesario el uso de los cualificadores no voraces:
*?, +?, ?? y {m,n}? que encajan en la menor cantidad de texto posible. En el caso del
ejemplo anterior deberamos usar <.*?> para que el motor pruebe con el segundo corchete justo
despus de haber coincidido el primero.
USANDO EXPRESIONES REGULARES
Ahora que conocemos las nociones bsicas podemos comenzar a utilizar Expresiones Regulares en
Python.
COMPILACIN DE EXPRESIONES REGULARES
Es el mdulo re el que nos proporciona una interfaz con el motor de expresiones regulares
permitindonos compilar las RE en objetos y posteriormente realizar las comparaciones con ellos.
Estos objetos nos proporcionan diferentes mtodos para realizar operaciones como bsquedas de
coincidencias o la sustitucin de cadenas:
>>> import re
>>> p = re.compile('ab*')
>>> p
<_sre.SRE_Pattern object at 0x...>
Las RE se pasan a re.compile() como una cadena de texto, esto se debe a que las RE no forman
parte del ncleo de Python y no tienen una sintaxis propia sino que re es una extensin para el
mdulo en C incluido en Python al igual que sockets o zlib.
Esto simplifica el lenguaje pero complica el escapado de caracteres especiales, que como
mencionamos anteriormente, puede solventarse mediante la notacin en crudo de cadenas.
re.compile() admite banderas de compilacin que nos permiten introducir variaciones en la
sintaxis. Las banderas del mdulo re tienen un nombre largo y uno corto que podemos usar
indistintamente (El nombre corto es el mismo que los modificadores para patrones en Perl). Es
posible especificar varias banderas mediante el operador de bits OR:
>>> p = re.compile('ab*', re.I | re.M)
PGINA 6
Esta tabla ilustra las diferentes banderas y el efecto que producen, para una descripcin detallada
revise la seccin 7.2.2 de la documentacin oficial Module Contents:
Bandera Efecto
DOTALL, S Hace coincidir . Con cualquier carcter, incluida la nueva lnea.
IGNORECASE, I Caso Insensitivo.
LOCALE, L Tiene en cuenta la locale actual.
MULTILINE, M Coincidencia Multi-lnea (afecta a ^ y $).
VERBOSE, X Activa el modo detallado, que permite escribir las RE de una forma ms
legible.
UNICODE, U Hace algunos caracteres especiales como \w, \b, \s y \d dependientes de la
base de datos de caracteres Unicode.
ENCAJANDO PATRONES
Una vez que tenemos el patrn compilado podemos comenzar a emplear sus mtodos y atributos.
Aqu veremos los ms importantes, para una lista completa consulte la documentacin oficial del
mdulo re.
Mtodo/Atributo Propsito
match() Determina si la RE encaja desde el principio de la cadena.
search() Escanea la cadena buscando la coincidencia en cualquier lugar.
findall() Encuentra todas las sub-cadenas donde encaja la RE y las retorna como
una lista.
finditer() Encuentra todas las sub-cadenas donde encaja la RE y las retorna como un
iterador.
match() y search() retornan None si no existe coincidencia alguna. Si tienen xito retornan un
objeto coincidencia, que contiene informacin sobre la misma: Inicio, fin, sub-cadena encajada y
mucho ms.
Si tienes Tkinter instalado tal vez te interese echar un vistazo a Tools/scripts/redemo.py, un
programa de demostracin incluido en la propia distribucin de Python que te permite introducir
REs y cadenas, y mostrar cuando la RE encaja o falla. Este script puede ser til cuando intentamos
depurar una RE complicada.
Otra herramienta interactiva interesante para el desarrollo y testeo de REs es Kodos, creada por
Phil Schwartz.
Tambin existen herramientas on-line como Pythex de Gabriel Rodrguez o Regex101, que es capaz
de explicar REs en diferentes lenguajes, ambas inspiradas en Rubular.
PGINA 7
Usaremos el intrprete estndar de Python para los siguientes ejemplos. Para comenzar cargue el
intrprete importe el mdulo re y compile una RE:
Python 2.2.2 (#1, Feb 10 2003, 12:57:01)
>>> import re
>>> p = re.compile('[a-z]+')
>>> p #doctest: +ELLIPSIS
<_sre.SRE_Pattern object at 0x...>
Ya podemos encajar diferentes cadenas contra la RE [a-z]+. Una cadena vaca no encajar debido
a que + significa al menos una repeticin. Usaremos print() para visualizar esto en el intrprete
ya que de lo contrario no obtendramos salida alguna:
>>> p.match("")
>>> print p.match("")
None
Ahora probaremos con tempo que debera encajar en la RE. En este caso match() retornar
un objeto coincidencia que almacenaremos en una variable para su posterior uso:
>>> m = p.match('tempo')
>>> m
<_sre.SRE_Match object at 0x...>
Ahora podemos preguntar al objeto coincidencia sobre la cadena encajada. Para ello, estos
objetos disponen de algunos mtodos y atributos, los ms importantes son:
Mtodo/Atributo Propsito
group() Retorna la sub-cadena encajada.
start() Retorna la posicin inicial en la que se produjo la coincidencia.
end() Retorna la posicin en la que termina la coincidencia.
span() Retorna una tupla (inicio, fin) con ambas posiciones.
Probaremos cada uno con el ejemplo anterior para ver los detalles:
>>> m.group()
'tempo'
>>> m.start(), m.end()
(0, 5)
>>> m.span()
(0, 5)
PGINA 8
Puesto que match() solo comprueba si la RE encaja desde el principio de la cadena, la posicin
inicial de la cadena ser siempre 0, sin embargo search() escanear la cadena entera:
>>> print p.match('::: message')
None
>>> m = p.search('::: message'); print m
<_sre.SRE_Match object at 0x...>
>>> m.group()
'message'
>>> m.span()
(4, 11)
En los programas actuales es comn almacenar el objeto coincidencia en una variable y comprobar
si fue None de la siguiente forma:
p = re.compile( ... )
m = p.match( 'string goes here' )
if m:
print 'Match found: ', m.group()
else:
print 'No match'
En ocasiones puedes estar tentado de usar re.match() y simplemente aadir .* al comienzo
de la RE. No lo hagas y utiliza re.search() en su lugar. El compilador de REs las analiza para
acelerar el proceso de bsqueda, por ejemplo, un patrn que contenga Cuervo debe encajar
en una cadena que comience por C. El anlisis permite al motor escanear rpidamente la cadena
buscando el carcter inicial y probando el resto solo si lo encuentra. Al aadir .* fuerzas al
motor de emparejamiento a escanear la cadena hasta el final y volver hacia atrs para encontrar
la coincidencia con el resto de la RE.
findall() retorna una lista de cadenas coincidentes, este mtodo necesita crear la lista completa
antes de poder retornarla como resultado:
>>> p = re.compile('\d+')
>>> p.findall('12 drummers drumming, 11 pipers piping, 10 lords a-
leaping')
['12', '11', '10']
PGINA 9
Por ultimo finditer() retorna una secuencia de instancias de objeto coincidencia como un
iterador:
>>> iterator = p.finditer('12 drummers drumming, 11 ... 10 ...')
>>> iterator
<callable-iterator object at 0x...>
>>> for match in iterator:
... print match.span()
...
(0, 2)
(22, 24)
(29, 31)
FUNCIONES DEL MDULO
No es estrictamente necesario compilar las RE antes de utilizarlas, re proporciona funciones de
alto nivel llamadas match(), search(), findall(), sub() entre otras. Estas funciones toman
los mismos argumentos que sus homologas del objeto patrn con la RE en forma de cadena como
primer argumento y retornan lo mismo: None o una instancia de objeto coincidencia.
>>> print re.match(r'From\s+', 'Fromage amk')
None
>>> re.match(r'From\s+', 'From amk Thu May 14 19:12:10 1998')
<_sre.SRE_Match object at 0x...>
Realmente, lo que hacen estas funciones es crear el objeto RE por ti y llaman sobre l al mtodo
correspondiente. Tambin almacenan dicho objeto en una cach para que las subsiguientes
llamadas sean ms rpidas.
Utilizar estas funciones o no, depende de la cantidad de veces que se use la RE y del estilo de
codificacin de cada uno. Si el programa utiliza muchas RE o si reusa las mismas en diferentes
partes puede ser til agrupar las definiciones en un mismo lugar y compilarlas a la vez, por otro
lado, si la RE se utiliza puntualmente estas funciones pueden resultar ms convenientes.
FUNCIONES DE CADENAS
Establecer coincidencias en diferentes conjuntos de caracteres junto con las repeticiones son las
principales capacidades distintivas de las RE. Sin embargo, no siempre es adecuado usar
expresiones regulares. Si queremos comprobar coincidencias contra una cadena fija o un solo
carcter, no estaremos usando ninguna de las caractersticas de las RE.
El tipo cadena dispone de algunos mtodos para realizar operaciones con cadenas fijas que suelen
ser bastante ms rpidos debido a que se implementan con un pequeo bucle en lugar de usar un
motor completo.
PGINA 10
Por ejemplo, si queremos reemplazar la ocurrencia cara por cruz considere utilizar
replace() en lugar de re.sub(). Ntese que replace() tambin sustituye la ocurrencia dentro
de las propias palabras, transformando caracol en cruzcol, para evitar esto
necesitaramos usar el patrn \bcara\b ya que este tipo de operaciones sobrepasan las
capacidades de replace().
Otra tarea comn es eliminar la ocurrencia de un solo carcter o reemplazarlo por otro,
translate() puede hacer ambas cosas y ser siempre ms rpido que cualquier expresin regular.
En sntesis, si los mtodos de cadenas son suficiente, son preferibles a las expresiones regulares.
PATRONES AVANZADOS
MS META-CARACTERES
Hay Meta-caracteres que no hemos visto an, cubriremos la mayora en esta seccin.
Los Meta-caracteres restantes caracteres son afirmaciones de ancho cero. No provocan que el
motor consuma caracteres de la cadena, simplemente tienen xito o fallan. Por ejemplo, \b es
una afirmacin que indica que la posicin actual se sita en los lmites de una palabra, pero no
cambia dicha posicin, por ende este tipo de Meta-caracteres no debe llevar modificadores de
repeticin puesto que si tienen xito una vez, tambin lo tendrn un nmero infinito de veces.
|
Es el operador lgico OR. Si A y B son expresiones regulares, A|B coincidir con cualquier
cadena que encaje en A o en B. Tiene muy baja precedencia para que tenga un
comportamiento razonable a la hora de alternar cadenas con varios caracteres.
Crow|Servo encajar tanto con Crow como con Servo, y no en Cro o w
ni en S o ervo.
Para encajar contra el literal |, use \| o encirrelo en los corchetes de clase: [|].
^
A menos que se especifique la bandera MULTILINE, encajar solamente al inicio de la
cadena. En modo Multi-lnea encaja inmediatamente despus de cada nueva lnea:
>>> print re.search('^From', 'From Here to Eternity')
<_sre.SRE_Match object at 0x...>
>>> print re.search('^From', 'Reciting From Memory')
None
PGINA 11
$
Encaja al final de la lnea, la cual se define como el final de la cadena o la posicin
siguiente al carcter de nueva lnea.
>>> print re.search('}$', '{block}')
<_sre.SRE_Match object at 0x...>
>>> print re.search('}$', '{block} ')
None
>>> print re.search('}$', '{block}\n')
<_sre.SRE_Match object at 0x...>
Para encajar contra el literal $, use \$ o encirrelo en los corchetes de clase: [$].
\A
Encaja exclusivamente al inicio de la cadena. Si no se especifica la bandera MULTILINE
\A y ^ son equivalentes.
\Z
Encaja exclusivamente al final de la cadena.
\b
Lmite de palabra. Encaja solo al principio o al final de una palabra, la cual se define como
una secuencia de caracteres alfanumricos separados por un carcter blanco o uno no-
alfanumrico.
El siguiente ejemplo coincide si class constituye una palabra por s misma y falla en
caso contrario:
>>> p = re.compile(r'\bclass\b')
>>> print p.search('no class at all')
<_sre.SRE_Match object at 0x...>
>>> print p.search('the declassified algorithm')
None
>>> print p.search('one subclass is')
None
PGINA 12
Hay dos detalles que debemos tener presentes: El primero es que esta secuencia es el
peor caso de colisin entre la representacin de cadenas de literales en Python y las
secuencias de expresiones regulares debido a que \b es el carcter de retroceso (valor
8 en ASCII). Si no utilizas notacin en crudo tu expresin regular no tendr el
comportamiento esperado. El siguiente ejemplo es igual al anterior, salvo que omite el
prefijo r:
>>> p = re.compile('\bclass\b')
>>> print p.search('no class at all')
None
>>> print p.search('\b' + 'class' + '\b')
<_sre.SRE_Match object at 0x...>
El segundo es que no tiene caso dentro de la definicin de la clase de un carcter, \b
representa el carcter de retroceso por razones de compatibilidad.
\B
Es el opuesto de \b, encaja cuando la posicin actual no est situada en el lmite de
una palabra.
AGRUPAMIENTO
Frecuentemente necesitamos obtener ms informacin a parte de si la RE encaja o no en una
cadena. Las expresiones regulares se usan a menudo para diseccionar cadenas subdividiendo la RE
en grupos que encajan en los distintos componentes de inters. Por ejemplo, las lneas de la
cabecera de una RFC-822 se compone de un nombre y un valor separados por : de la siguiente
forma:
From: author@example.com
User-Agent: Thunderbird 1.5.0.9 (X11/20061227)
MIME-Version: 1.0
To: editor@example.com
Podemos conseguir esto escribiendo una RE que encaje en cada lnea y tenga dos grupos, uno para
el nombre y otro para el valor.
Los grupos se encuadran entre los Meta-caracteres (, ) y agrupan las expresiones que
contienen. Se pueden repetir los contenidos de un grupo mediante los cuantificadores *, +,
? o {m, n}. Por ejemplo (ab)+ encaja con una o ms repeticiones del grupo ab:
>>> p = re.compile('(ab)*')
>>> print p.match('ababababab').span()
(0, 10)
PGINA 13
Los grupos van numerados de izquierda a derecha comenzando desde 0. El grupo 0 siempre est
presente y corresponde a la RE entera, adems cada grupo captura el ndice inicial y final del
texto donde encaja, para recuperarlos se puede pasar como argumento el nmero del grupo a los
mtodos group(), start(), end(), and span():
>>> p = re.compile('(a)b')
>>> m = p.match('ab')
>>> m.group()
'ab'
>>> m.group(0)
'ab'
Los grupos pueden estar anidados, para determinar el nmero basta con contar los parntesis
abiertos de izquierda a derecha:
>>> p = re.compile('(a(b)c)d')
>>> m = p.match('abcd')
>>> m.group(0)
'abcd'
>>> m.group(1)
'abc'
>>> m.group(2)
'b'
A group() se le pueden pasar varios grupos a la vez, en tal caso retornar una tupla conteniendo
los valores correspondientes a tales grupos:
>>> m.group(2,1,2)
('b', 'abc', 'b')
Si no se especifica ningn argumento la tupla contendr las cadenas de todos los grupos existentes:
>>> m.groups()
('abc', 'b')
Las referencias hacia atrs nos permiten especificar que el contenido de un grupo previamente
capturado debe encontrarse en la posicin actual de la cadena. Por ejemplo \1 tendr xito si
el contenido del grupo 1 se encuentra en la posicin actual y falla en caso contrario.
Recuerda que en Python se utiliza la barra invertida seguida de nmeros para denotar caracteres
arbitrarios en las cadenas de literales, por tanto asegrate de usar la notacin en crudo cuando
introduzcas referencias hacia atrs en una RE.
PGINA 14
Por ejemplo, la siguiente RE detecta palabras repetidas en una cadena:
>>> p = re.compile(r'(\b\w+)\s+\1')
>>> p.search('Paris in the the spring').group()
'the the'
Las referencias hacia atrs como esta, apenas se usan en bsquedas, pero son de gran utilidad a
la hora de realizar sustituciones de texto.
GRUPOS ETIQUETADOS Y GRUPOS NO-CAPTURADOS
Tenemos dos caractersticas que nos ayudan a lidiar con este problema, ambas utilizan la misma
sintaxis para la extensin de expresiones regulares, por lo que examinaremos esto primero:
Perl 5 aadi algunas caractersticas a las expresiones regulares standard y el mdulo re de Python
soporta la mayora. Hubiera sido difcil elegir un nuevo Meta-carcter o secuencia especial
comenzando con \ para representar estas nuevas caractersticas sin hacerlo ms confuso o variar
el standard de Perl.
La solucin elegida por los desarrolladores fue usar (...) como extensin de la sintaxis. ?
inmediatamente despus de parntesis provocara un error debido a que no habra nada que
repetir y por tanto mantendra la compatibilidad. Los caracteres siguientes a ? indican el tipo
de extensin utilizada, de esta forma tenemos que (?=foo) es una cosa (Una afirmacin de
bsqueda hacia delante positiva) y (?:foo) otra distinta (Un grupo no-capturado que contiene
la sub-expresin foo).
Python a su vez aade una extensin sintctica a la extensin sintctica de Perl. Si el siguiente
carcter a ? es P, estamos ante una extensin propia de Python. Actualmente estas
extensiones son dos: (?P<nombre>...) define un grupo etiquetado y (?P=nombre) es una
referencia hacia atrs a un grupo etiquetado. Si en un futuro la sintaxis de Perl variase, el mdulo
re se cambiara para soportar la nueva sintaxis a la vez que se preservan las extensiones
especficas de Python por compatibilidad.
Ahora que conocemos la sintaxis general para extensiones podemos centrarnos en las
caractersticas para trabajar con grupos en REs complejas:
Las REs ms elaboradas pueden llegar a utilizar muchos grupos tanto para capturar sub-cadenas
de inters como para estructurar la RE en s misma. En REs complejas se hace difcil seguir la pista
de los nmeros de grupo y se hace molesto introducir nuevos grupos, especialmente al comienzo
de la RE, debido a que la numeracin de los grupos subsiguientes cambiara.
Podemos solventar esto con grupos etiquetados: en lugar de referenciar un grupo con un nmero,
los referenciamos con un nombre.
PGINA 15
La sintaxis para los grupos etiquetados es especfica de Python: (?P<nombre>...), donde
nombre es el nombre del grupo. Los grupos etiquetados tienen exactamente el mismo
comportamiento que los grupos, con el aadido de estar asociados a un nombre. Los mtodos de
los objetos coincidencia pueden lidiar con ambas referencias:
>>> p = re.compile(r'(?P<word>\b\w+\b)')
>>> m = p.search( '(((( Lots of punctuation )))' )
>>> m.group('word')
'Lots'
>>> m.group(1)
'Lots'
La sintaxis de las referencias hacia atrs del tipo ()\1 refieren a grupos mediante su nmero.
Existe una variante que permite hacerlo mediante el nombre, es otra de las extensiones
especficas de Python: (?:nombre) indica que el contenido del grupo nombrado debe estar
presente de nuevo en el punto actual. La RE para encontrar palabras repetidas (\b\w+)\s+\1
puede ser reescrita como: (?P<word>\b\w+)\s+(?P=word)
>>> p = re.compile(r'(?P<word>\b\w+)\s+(?P=word)')
>>> p.search('Paris in the the spring').group()
'the the'
A veces ocurre que queremos recoger parte de una expresin regular pero no estamos interesados
en recuperar los contenidos del grupo, esto se puede explicitar utilizando grupos no-capturados:
(?:...) donde podemos reemplazar ... con cualquier otra expresin regular:
>>> m = re.match("([abc])+", "abc")
>>> m.groups()
('c',)
>>> m = re.match("(?:[abc])+", "abc")
>>> m.groups()
()
Excepto por el hecho de que no podemos recuperar los contenidos del grupo coincidente, un grupo
no-capturado tiene el mismo comportamiento que un grupo capturado. Puedes poner cualquier
cosa dentro, emplear repeticiones y anidarlo en otro grupo (capturado o no capturado).
(?:...) es particularmente til al modificar REs existentes ya que no hace variar la numeracin
del resto de grupos.
No existen diferencias de rendimiento entre el uso de grupos capturados y no-capturados ni
tampoco es una forma ms rpida que la otra.
PGINA 16
ASERCIONES DE BSQUEDA HACIA DELANTE
Otras afirmaciones de ancho cero son las aserciones de bsqueda hacia delante. Pueden
expresarse de forma positiva o negativa:
(?=...)
Asercin positiva de bsqueda hacia delante. Tiene xito cuando la RE contenida,
representada por ... encaja en la posicin actual y falla en caso contrario. Pero al
probar la expresin contenida en la asercin, el motor de emparejamiento no avanza y
continua probando el resto del patrn justo donde comenz la asercin.
(?!...)
Asercin negativa de bsqueda hacia delante. Es el opuesto del anterior, Tiene xito
cuando la RE contenida no encaja y falla en caso contrario.
Para detallar esto veamos un caso concreto en el que las aserciones de bsqueda hacia delante
son de utilidad: Consideremos un patrn simple que encaje en un nombre de fichero compuesto
por un nombre y una extensin separados por .. Por ejemplo news.rc donde news es el
nombre y rc la extensin:
El patrn es bastante simple: .*[.].*$
Ntese que . Necesita un tratamiento especial por ser un Meta-carcter y para hacerlo encajar
con su literal lo hemos encerrado en la definicin de clase. Tambin el $ final asegura que el
resto de la cadena est incluida en la extensin. Esta RE encaja con foo.bar,
autoexec.bat, sendmail.cf y printers.conf.
Ahora lo complicaremos un poquito ms: Qu ocurrira si quisiramos encajar con los nombres de
archivo que no tengan extensin bat? Algunos intentos incorrectos seran los siguientes:
.*[.][^b].*$
Este primer intento excluye la extensin bat requiriendo que el primer carcter no sea b.
Esto est mal porque no encajara en foo.bar.
PGINA 17
.*[.]([^b]..|.[^a].|..[^t])$
La expresin se vuelve ms confusa cuando intentamos parchear el primer intento requiriendo
uno de los tres siguientes casos para que se produzca la coincidencia: Que el primer carcter no
sea una b, que el segundo no sea una a o que el tercero no sea una t. Esto acepta foo.bar
y rechaza autoexec.bat pero exige que la extensin tenga tres letras. Un nombre de fichero
con una extensin de dos letras como sendmail.cf sera rechazado. Complicaremos la
expresin un poco ms para intentar solucionarlo:
.*[.]([^b].?.?|.[^a]?.?|..?[^t]?)$
En este tercer intento la segunda y tercera letras de la extensin son opcionales para permitir que
encajen nombres de fichero que tengan menos de tres letras en su extensin.
El patrn se ha vuelto bastante complicado, lo que lo hace difcil de leer y comprender. An peor,
si el problema cambia y adems de bat quisiramos excluir tambin exe, el patrn se
complicara an ms.
Las aserciones de bsqueda hacia delante vienen a simplificar este tipo de casos. Reformulando
el patrn con una asercin negativa quedara:
.*[.](?!bat$).*$
La asercin negativa significa: Si la expresin bat no encaja en este punto, prueba el resto del
patrn, si bat$ encaja el patrn entero fallar. El $ del final es necesario para que algo como
simple.batch donde la extensin solo comienza con bat se permita.
Ahora excluir una extensin adicional es tan simple como aadir un OR en la asercin. El siguiente
patrn excluye tanto bat como exe:
.*[.](?!bat$|exe$).*$
MODIFICANDO CADENAS
Hasta ahora solo hemos buscado coincidencias en cadenas. Las expresiones regulares tambin se
usan normalmente para modificar cadenas de distintas formas, usando los siguientes mtodos:
Mtodo/Atributo Propsito
split() Parte la cadena en una lista, cortando all donde la RE coincida.
sub() Encuentra las sub-cadenas donde la RE coincida y las reemplaza por otra
diferente.
subn() Igual que sub(), pero retorna la nueva cadena y el nmero de reemplazos.
PGINA 18
PARTIENDO CADENAS
El mtodo split() de un patrn es similar al split() de una cadena, pero es mucho ms flexible
en cuanto a los delimitadores que se pueden utilizar para realizar el corte, el split() de las
cadenas solo soporta el corte en los caracteres blancos o en sub-cadenas fijas.
.split(cadena[, maxcorte=0])
Podemos limitar el nmero de cortes fijando un valor para maxcorte. Si maxcorte no es 0, se
realizarn como mucho maxcorte cortes y el resto de la cadena se retornar como ltimo valor
de la lista. En el siguiente ejemplo el delimitador es cualquier secuencia de caracteres no
alfanumricos:
>>> p = re.compile(r'\W+')
>>> p.split('This is a test, short and sweet, of split().')
['This', 'is', 'a', 'test', 'short', 'and', 'sweet', 'of', 'split', '']
>>> p.split('This is a test, short and sweet, of split().', 3)
['This', 'is', 'a', 'test, short and sweet, of split().']
A veces no solo estamos interesados en conocer el texto entre delimitadores, sino tambin en el
delimitador que provoc el corte. Si usamos grupos en la RE, sus valores capturados tambin se
retornarn como parte de la lista. Compara las siguientes llamadas:
>>> p = re.compile(r'\W+')
>>> p2 = re.compile(r'(\W+)')
>>> p.split('This... is a test.')
['This', 'is', 'a', 'test', '']
>>> p2.split('This... is a test.')
['This', '... ', 'is', ' ', 'a', ' ', 'test', '.', '']
Como mencionamos anteriormente, podemos usar directamente la funcin del mdulo re.split()
en lugar de las del objeto patrn, con la salvedad de que debemos aadir la RE usada como primer
argumento:
>>> re.split('[\W]+', 'Words, words, words.')
['Words', 'words', 'words', '']
>>> re.split('([\W]+)', 'Words, words, words.')
['Words', ', ', 'words', ', ', 'words', '.', '']
>>> re.split('[\W]+', 'Words, words, words.', 1)
['Words', 'words, words.']
PGINA 19
BSQUEDA Y REEMPLAZO
Otra tarea comn es reemplazar una cadena por otra. El mtodo sub() toma un valor de
reemplazo, que puede ser otra cadena o una funcin y la cadena a procesar:
.sub(reemplazo, cadena[, cont=0])
Este es un ejemplo simple en el que se reemplazan los nombres de los colores por la cadena
colour:
>>> p = re.compile( '(blue|white|red)')
>>> p.sub( 'colour', 'blue socks and red shoes')
'colour socks and colour shoes'
>>> p.sub( 'colour', 'blue socks and red shoes', count=1)
'colour socks and red shoes'
El mtodo subn() funciona del mismo modo, pero retorna una tupla con la nueva cadena y el
nmero de reemplazos:
>>> p = re.compile( '(blue|white|red)')
>>> p.subn( 'colour', 'blue socks and red shoes')
('colour socks and colour shoes', 2)
>>> p.subn( 'colour', 'no colours at all')
('no colours at all', 0)
Las coincidencias vacas solo se reemplazan cuando no son adyacentes a la coincidencia anterior:
>>> p = re.compile('x*')
>>> p.sub('-', 'abxd')
'-a-b-d-'
Si el reemplazo es una cadena; cualquier secuencia escapada con una barra invertida se procesa,
es decir, \n se convierte en una nueva lnea, \r en un retorno de carro, etc. Si no se conoce
la secuencia escapada se deja igual.
Las referencias hacia atrs, como \6, se reemplazan por el grupo correspondiente en la RE. Esto
permite incorporar porciones del texto original en la cadena resultante tras el reemplazo.
El siguiente ejemplo encaja con la palabra section seguida de una cadena encerrada entre
corchetes {, } y cambia section por subsection:
>>> p = re.compile('section{ ( [^}]* ) }', re.VERBOSE)
>>> p.sub(r'subsection{\1}','section{First} section{second}')
'subsection{First} subsection{second}'
PGINA 20
Tambin hay una sintaxis para los grupos etiquetados, definidos por (?P<nombre>...).
\g<nombre> usar la sub-cadena coincidente con el grupo llamado nombre y
\g<nmero> el correspondiente grupo numerado. \g<2> es por tanto equivalente a \2,
pero no es ambiguo en un reemplazo de cadena tal como: \g<2>0 (\20 sera interpretado como
una referencia al grupo 20 en lugar de una referencia al grupo 2 seguida de 0). Las siguientes
sustituciones son equivalentes, pero usan cada una de las tres variantes:
>>> p = re.compile('section{ (?P<name> [^}]* ) }', re.VERBOSE)
>>> p.sub(r'subsection{\1}','section{First}')
'subsection{First}'
>>> p.sub(r'subsection{\g<1>}','section{First}')
'subsection{First}'
>>> p.sub(r'subsection{\g<name>}','section{First}')
'subsection{First}'
reemplazo tambin puede ser una funcin, lo que nos proporciona incluso ms control, en tal
caso la funcin es llamada en cada ocurrencia no solapante en el patrn. En cada llamada se le
pasa a la funcin un objeto coincidencia con la informacin de la coincidencia actual, que puede
utilizar para computar el reemplazo deseado y retornarlo.
En el siguiente ejemplo la funcin traduce dgitos decimales a hexadecimales:
>>> def hexrepl(match):
... "Return the hex string for a decimal number"
... value = int(match.group())
... return hex(value)
...
>>> p = re.compile(r'\d+')
>>> p.sub(hexrepl, 'Call 65490 for printing, 49152 for user code.')
'Call 0xffd2 for printing, 0xc000 for user code.'
PGINA 21
RECURSOS Y HERRAMIENTAS DE DESARROLLO Y DEPURACIN
ONLINE
Pythex
De Gabriel Rodrguez, inspirada en Rubular.
Regex101
Herramienta capaz de explicar el significado de una RE en diferentes lenguajes.

OFF-LINE
Redemo.py
Programa de demostracin incluido en la propia distribucin de Python (situado en
tools/scripts/redemo.py, necesita Tkinter).
Kodos
Herramienta creada por Phil Schwartz.
REFERENCIAS
Documentacin Oficial de Python sobre el mdulo re.
Regular Expression HOWTO de A.M. Kuchling.

También podría gustarte