Expresiones regulares en python

De ChuWiki

Veamos algunos ejemplos de cómo usar expresiones regulares en python. No vamos a ver el detalle de la sintaxis de las expresiones regulares, eso puedes verlo en Introduccion a las expresiones regulares.

El código de estos ejemplos funciona con python 3.6, más que nada porque se usa para formatear cadenas la forma f"....", que es nueva en esta versión y no compatible con versiones anteriores.

String con expresión regular en Python[editar]

En python una expresión regular se mete en un string normal, por ejemplo "[a-z]+" para encontrar las letras de a a z una o más veces.

Si la expresión regular lleva el caracter \ es necesario "escaparlo", añadiendo delante otro \, por ejemplo, "\\d" para buscar una cifra.

Si la expresión lleva demasiados caracteres \, puede ser un poco lío duplicarlos todos. python contempla los raw string, en los que los caracteres se ponen tal cual y no se interpreta ninguno, por lo que no hace falta "escapar" ninguno. Estas cadenas raw string se hacen anteponiendo una r de las comillas. Por ejemplo, en vez de "\\d", podemos poner r"\d"

Buscar con expresión regular en cadena[editar]

Podemos buscar uno o más subcadenas dentro de la cadena que cumplan con la expresión regular. Debemos importar el módulo re de regular expression para poder usar las funciones de python que nos permiten hacer estas búsquedas. Veamos dichas funciones

Búsqueda al principio de la cadena re.match()[editar]

La función re.match(expresion,cadena) busca si el principio de la cadena cumple la expresión. Si la no la cumple devuelve None. Si la cumple devuelve un objeto match con los datos de lo que ha encontrado. Veamos algún ejemplo

# re.match busca al principio de la cadena. Devuelve None
match= re.match(r'\d', 'a1234')
print(match)
if (match == None):
    print("No se encuentra número al principio de la cadena")

# re.match busca al principio de la cadena. Encuentra el 1.
match= re.search('\\d', '1234')
print(match)
if (match != None):
    print(f"encontrado {match.group()}")
    print(f"desde posición {match.start()} hasta {match.end()}")

En el primer bloque de código hemos usado un raw string para buscar una cifre \d al principio de la cadena. Como la cadena empieza con una a, la función match devolverá None y entraremos en el if.

En el segundo bloque, no usamos raw string, por lo que hemos tenido que poner doble \\d. Aquí la cadena empieza con un 1, por lo que lo encontrará. La salida será la siguiente

El print(match) devuelve una representación en string del objeto match

<_sre.SRE_Match object; span=(0, 1), match='1'>

print(f"encontrado {match.group()}") devuelve el texto encontrado, el 1 en este caso

encontrado 1

Finalmente, print(f"desde posición {match.start()} hasta {match.end()}") devuelve la posición en la que se ha encontrado (dese posición 0) y la posición final de la subcadena excluída (posición 1)

desde posición 0 hasta 1

Búsqueda en la cadena re.search()[editar]

La función re.search(expresión,cadena) busca la primera subcadena que cumpla la expresión dentro de cadena, en cualquier posición, no sólo al principio como hacía re.match(). Veamos un pequeño ejemplo

# re.search busca a lo largo de la cadena. el 1.
match= re.search('\\d', 'a1234')
print(match)
if (match != None):
    print(f"encontrado {match.group()}")
    print(f"desde posición {match.start()} hasta {match.end()}")

Esto encontraría el primer dígito de la cadena, el 1 y sacaría por pantalla

<_sre.SRE_Match object; span=(1, 2), match='1'>
encontrado 1
desde posición 1 hasta 2

Todas las búsquedas en la cadena re.findall()[editar]

re.findall(expresion,cadena) busca todas las subcadenas dentro de cadena que cumplan la expresión regular. Nos devuelve una lista de los string que ha encontrado. Veamos el código de ejemplo

# re.findall devuelve una lista con todo lo que encuentra
matchList= re.findall(r'\d', '1234')
print(matchList)
print("Se ha encontrado {} veces".format(len(matchList)))
for value in matchList:
    print(value)

Esto saca por pantalla

['1', '2', '3', '4']
Se ha encontrado 4 veces
1
2
3
4

Si metemos grupos de búsqueda (entre paréntesis) en la expresión regular, findall() devolverá tuplas con los grupos, tantas como encuentre. El siguiente ejemplo muestra cómo extraer las fechas de una cadena que contiene varias fechas.

# r.findall con grupos
match = re.findall(r'(\d+)/(\d+)/(\d+)','11/12/2017 5/3/2014 9/1/1994')
print(match)
for value in match:
    print(f'dia={value[0]}, mes={value[1]}, año={value[2]}')

En la expresión regular hemos metido \d+ para búsqueda del día, del mes y del año. Los hemos puesto entre paréntesis porque nos interesa extraer esas cifras por separado. El resultado del código es

[('11', '12', '2017'), ('5', '3', '2014'), ('9', '1', '1994')]
dia=11, mes=12, año=2017
dia=5, mes=3, año=2014
dia=9, mes=1, año=1994

El print(match) devuelve una lista de tuplas, donde cada tupla tiene las cifras (día, mes y año) de una fecha. En el bucle, vamos obteniendo día, mes y año por separado, indicando el índice 0,1 ó 2 del elemento dentro de la tupla.

Compilar una expresión regular[editar]

Si la expresión regular vamos a usarla varias veces, podemos compilarla para obtener un Pattern (patrón) con métodos match(), search() y findall() similares a los que hemos usado hasta ahora, pero sin necesidad de meter la expresión regular como parámetro. Veamos un ejemplo sencillo de cada uno de estos métodos

# Se puede compilar una expresión regular para usarla varias veces.
pattern = re.compile(r"\d\d")

match = pattern.match("123")
print(f'pattern.match() = {match.group()}')

match = pattern.search("abc123")
print(f'pattern.search() = {match.group()}')

matchList = pattern.findall("12-34-567")
for value in matchList:
    print(f'pattern.findall() = {value}')

que por pantalla sacaría

pattern.match() = 12
pattern.search() = 12
pattern.findall() = 12
pattern.findall() = 34
pattern.findall() = 56

Flags en las expresiones regulares[editar]

Todos estos métodos, tanto de re como de pattern admiten un parámetro adicional con flags para indicar algún detalle de la búsqueda. Por ejemplo, es interesante el de IGNORECASE, para indicar que nos da igual en la búsqueda las mayúsculas y minúsculas. Veamos un ejemplo

re.search("hola","HOLA",re.IGNORECASE)

se cumpliría en este caso la expresión regular, puesto que ignoramos mayúsculas y minúsculas.

Hay otros flags que puedes ver en la documentación de referencia (enlace al final).

Extracción de grupos[editar]

Aunque ya hemos visto algo con findall(), podemos hacer una búsqueda normal con match() o search() poniendo grupos entre paréntesis en la expresión regular. Podemos obtener fácilmente el contenido de esos grupos en la cadena real. Por ejemplo, para extraer los datos de una fecha

match = re.match(r"(\d+)/(\d+)/(\d+)", "11/12/2014")
print (match.group())
print (match.groups())
for value in match.groups():
    print(value)

Que sacaría por pantalla lo siguiente

11/12/2014
('11', '12', '2014')
11
12
2014
  • match.group() devuelve la cadena completa que ha cumplido la expresión regular completa, es decir, 11/12/2014
  • match.groups() devuelve una tupla con todos los grupos parciales encontrados, es decir, ('11', '12', '2014')
  • Sin más que hacer un bucle sobre esa tupla podemos ir obteniendo cada uno de los valores concretos.

Enlaces[editar]