Expresiones regulares en python pt2



@eduardo_gpg

Número de visitas 1458

Tiempo de lectura 5 min

11 Julio 2020

En el post anterior tuvimos nuestro primer acercamiento con las expresiones regulares en Python. 🐍 Trabajamos con el módulo re y con los métodos match y search. Sin embargo es importante mencionar que estos no son los únicos métodos que nos permitirán implementar nuestras expresiones regulares. Es por ello que en esta ocasión, para esta segunda entrega, me gustaría listar un par de métodos más que sin dudas nos serán de mucha utilidad.

Bien, sin más que decir, pongamos manos a la obra.

Repaso

🐍 Un dato interesante es que a partir de la versión 1.5 de Python se introdujo las expresiones regulares, esto al estilo Perl.

Si recordamos el primer paso para implementar una expresión regular es compilar nuestro patrón, y para ellos nos apoyamos de la función compile. Esta función retorna un objeto de tipo RegexObject . Lo interesante de trabajar con este tipo de objetos es la gran cantidad de métodos que posee, pudiendo así implementar nuestras expresiones regulares sobre la n cantidad de strings que deseemos. 🐉

El primer método que utilizamos con este objeto fue el método match, el cual nos permite conocer si una expresión regular se encuentra al inicio de la cadena. Si existe una coincidencia el método retorna un objeto de tipo Match, en caso contrario None.

>>> pattern = re.compile(r'PyWombat') 
>>> pattern.match("PyWombat")                  
<re.Match object; span=(0, 8), match='PyWombat'>

Es importante conocer que el método match posee 2 parámetros de suma importancia, me refiero a pos y endpos. Utilizando estos parámetros seremos capaces de indicar, donde queremos que comiences y finalice la búsqueda.

# La búsqueda comienza a partir de la posición 11 hasta la posición 19
>>> pattern.match("Hola desde PyWombat", pos=11, endpos=19) 
<re.Match object; span=(11, 19), match='PyWombat'>

De igual forma trabajamos con el método search. A diferencia del método match, el método search busca coincidencias sobre toda la cadena. Si existe una coincidencia el método retorna un objeto de tipo Match, en caso contrario None. 🤠

>>> pattern.search("Hola desde PyWombat")                                                       
<re.Match object; span=(11, 19), match='PyWombat'>

Justo como el método match, con el método search podremos indicar dónde deseamos que comience y finalice la búsqueda.

# La búsqueda comienza a partir de la posición 5 hasta la posición 19
>>> pattern.search("Hola desde PyWombat", pos=5, endpos=19)                                     
<re.Match object; span=(11, 19), match='PyWombat'>

Entonces recordemos: Siempre que deseemos implementar una expresión regular trabajaremos con 2 tipos de objetos: RegexObject, (el patrón previamente compilado) y MatchObject (la representación de patrón si existe coincidencia).

FindAll

Listo, ya podemos conocer si una expresión se encuentra, o no dentro de una cadena, esto mediante los métodos match y search, sin embargo estos métodos solo nos retornan la primera coincidencia, así que ¿Qué pasa si nuestra expresión puede encontrarse más de una vez? 🧐 En esos casos debemos utilizar el método findall. A diferencia de los métodos previamente mencionados, con el método findall obtendremos como resultado una lista con todas las coincidencias.

>>> items = """ 
    <div title="buyer-info"> 
        <span class="item-price">$8.37</span><br> 
    </div> 
        <div title="buyer-info"> 
    <span class="price item-price">$15.26</span><br> 
    </div> 
    <div title="buyer-info"> 
        <span class="item-price">$19.25</span><br> 
    </div> 
    <div title="buyer-info"> 
        <span class="item-price">$19.25</span><br> 
    </div> 
"""

>>> pattern = re.compile(r'<span class="item-price">(.+?)</span>') 
>>> pattern.findall(items) 
['$8.37', '$19.25', '$19.25']

Para este ejemplo, mediante la expresión regular (.+?), extraemos todo el contenido que se encuentre dentro de las etiquetas span.

FindIter

Otro método que nos puede ser de utilidad, es el método finditer. A diferencia del método findall, con finditer obtendremos como resultado un iterator con todas las coincidencias encontradas. 😲

>>> pattern.finditer(items)
 <callable_iterator at 0x10da6f898>

>>> for price in pattern.finditer(items): 
>>>     print(price) 

<re.Match object; span=(30, 67), match='<span class="item-price">$8.37</span>'>
<re.Match object; span=(193, 231), match='<span class="item-price">$19.25</span>'>
<re.Match object; span=(272, 310), match='<span class="item-price">$19.25</span>'>

Para temas de optimización, y siempre que trabajemos con una gran cantidad de datos, lo mejor que podemos hacer es utilizar un iterador sobre una lista, de esta forma no almacenaremos ningún objeto en memoria. 🤓

Replace

Listo, ya sabemos obtener coincidencias de un patrón dentro de un string, no obstante como mencionamos en el post anterior, las expresiones regulares también nos permiten modificar cadenas de texto, pudiendo, ya sea reemplazar porciones de texto o dividir grandes cadenas en fragmentos más pequeños. Así que aun nos falta hablar sobre un par de métodos más.

Comencemos reemplazando strings. Para ello haremos uso del método _ sub_. Este método retorna un nuevo string con los cambios previamente realizados.

Veamos un ejemplo, reemplazamos todos los números dentro de una cadena por asteriscos (*).

>>> pattern = re.compile(r'[0-9]')                                                              
>>>pattern.sub('*', 'simplepassword12345') 

'simplepassword*****'

Si así lo deseamos, mediante el parámetro count, podemos indicar la cantidad máxima de cambios ha realizar.🦖

# Reemplazamos solo los primeros 3 números dentro de la cadena
>>> pattern.sub('*', 'simplepassword12345', count=3)  
'simplepassword***45'

Una variante del método sub es subn. Este método se encarga de retornar, no un string, si no una tupla.

>>> pattern.subn('*', 'simplepassword12345')                                                    
('simplepassword*****', 5)

La tupla poseerá por valores, el nuevo string generado y la cantidad de coincidencias encontradas. 😋

Split

En dado caso deseemos dividir nuestra cadena de texto, haremos uso del método split. El método dará como resultado una lista a partir de las coincidencias obtenidas.

>>> pattern = re.compile(r"\W")                                                                 

>>> pattern.split('Hola mundo desde PyWombat')
['Hola', 'mundo', 'desde', 'PyWombat']

>>> pattern.split('Te?saludamos?desde?un?nuevo?post')
 ['Te', 'saludamos', 'desde', 'un', 'nuevo', 'post']

Para este par de ejemplos, mediante la expresión regular \W, dividimos nuestro string en cualquier carácter no alfanumérico. Las coincidencias ocurre para los espacios en blanco y los signos de interrogación (?).

Utilizando el parámetro maxsplit podremos indicar la cantidad máxima de splits que pueden ser realizados. 🤓

>>> pattern.split('Hola mundo desde un nuevo post', maxsplit=1) 
['Hola', 'mundo desde un nuevo post']

Podemos observar que para este ejemplo la división se realizo una sola vez, dando como resultado una lista con 2 elementos.


Listo, estos son algunos métodos que podemos encontrar en nuestros objetos RegexObject, por supuesto no son los únicos, pero sí, los que considero yo, con los que más estaremos trabajando en nuestro día a día.

En el siguiente post explicaremos el método Group y sus variantes. Es un tema muy interesante, así que no te lo puedes perder. 🥳

Entregas


¿El contenido te resulto de ayuda?

Para poder dejar tu opinión es necesario ser un usuario autenticado. Login