Expresiones Regulares En Python Pt3



@eduardo_gpg

Número de visitas 1441

Tiempo de lectura 4 min

12 Agosto 2020

En las entradas anteriores (Parte 1 y Parte 2) trabajamos con un par de objetos y métodos que sin duda nos serán de mucha utilidad al implementar expresiones regulares. Podemos concluir que ya tenemos los conocimientos básico, 😎 así que, ¿Qué te parece si comenzamos a subir el nivel de complejidad? Y para ello hablaremos del tema de grupos, un tema sin duda muy interesante. Veamos.

Grupos

Verás, los grupos son uno de los features más interesante que podremos encontrar en las expresiones regulares. A través de ellos seremos capaces de crear y agrupar sub strings, lo cual nos permitirá implementar nuevas expresiones sobre strings mucho más puntuales.

Para poder crear grupos debemos hacer uso de los matecaracteres de parentesis. Por ejemplo, agrupemos en 4 grupos todas las palabras de nuestro string. Un grupo por cada palabra.

>>> pattern = re.compile(r"(\w+) (\w+) (\w+) (\w+)")
>>> match = pattern.search("Hola mundo desde PyWombat")    
>>> match 
<re.Match object; span=(0, 25), match='Hola mundo desde PyWombat'>

Para nosotros acceder a cada uno de estos grupos podemos hacer uso del método group. Accederemos a los grupos mediante su indices.

A diferencia de las listas, los índices en los grupos podemos decir que comienzan en 1, ya que el índice 0 hace referencia al string per se.

# Sin argumentos
>>> match.group()
Hola mundo desde PyWombat

# Indice 1
>>> match.group(1)
Hola

# Indice 4
>>> match.group(4)
PyWombat

Si intentamos acceder a un grupo que no exista obtendremos un error.

>>> match.group(5)
IndexError: no such group

El uso de parentesis nos permite agrupar sub expresiones regulares.

Algo interesante de trabajar con grupos es la posibilidad de nombrarlos. Para nombrar aun grupo seguiremos la siguiente sintaxis (?P<name>pattern).

>>> pattern = re.compile(r"(?P<first>\w+) (?P<second>\w+) (?P<third>\w+) (?P<fourth>\w+)")
>>> match = pattern.search("Hello world desde PyWombat")  

>>> match.group('first')   
Hola

>>> match.group(1)
Hola

Cómo podemos observar, al nosotros nombrar los grupos podremos acceder a ellos ya sea por su nombre o indice.

En caso deseemos acceder a múltiples grupos, seamos que podemos hacerlo, basta con colocar como argumento los indices o nombres con los cuales deseamos trabajar. Obtendremos como resultado una tupla.

Por ejemplo. Obtengamos los dos primeros grupos junto con el último.

match.group('first', 'second', 4)

Ahora, ¿Qué pasa si deseamos conocer todos los grupos de nuestro objeto? La respuesta es sencilla, debemos hacer uso del método groups. Obtendremos como resultado una tupla.

>>> match.groups() 
('Hola', 'mundo', 'desde', 'PyWombat')

En caso deseemos conocer el grupo con su correspondiente nombre haremos uso del método groupdict.

>>>match.groupdict()                                                                             
{'first': 'Hola', 'second': 'mundo', 'third': 'desde', 'fourth': 'PyWombat'}

Start, End and Spand

Existen 3 métodos que nos permitirán conocer los indices en donde comienzan y finalizan los grupos.

  • start([GROUP])
  • end(group)
  • span(group)

Veamos un ejemplo.

>>> pattern = re.compile(r"(?P<first>\w+) (?P<second>\w+)?")  
>>> match = pattern.search('Hola mundo')
>>> match.group(1)  
'Hola'

# Índice donde comienza el primer grupo
>>> match.start(1)
0

# Índice donde finaliza el primer grupo
>>> match.end(1)
0

# Índices donde comienza y finaliza el primer grupo.
>>> match.span(1)
(0, 4)

Ok, ese ejemplo fue algo sencillo, así que practiquemos un poco más.

  • 2 grupos a partir de un número decimal.
>>>  pattern = re.compile(r"(\d+).(\d+)")
>>> match = pattern.search('3.14159')
>>> match.groups()
('3', '14159')
  • 3 grupos a partir de una fecha (Día-mes-año).
>>> pattern = re.compile('(\d{2})-(\d{2})-(\d{4})') 
>>> match = pattern.search('12-12-2020')
('12', '12', '2020')
  • 3 grupos a partir de una fecha (Día de mes del año).
>>> pattern = re.compile(r'(\d{2}) de (\w+) del (\d{4})')
>>> match = pattern.search('20 de agosto del 2020')
>>> match
('20', 'agosto', '2020')

Otra ventaja de utilizar grupos es la facilidad con la cual podremos aplicar diferentes opciones a nuestras expresiones regulares.

Consideremos el siguiente escenario: Debemos validar que un string comience la palabra: el. No importa si esta mayúsculas, minúsculas o ambas. Para este ejemplo como la palabra el solo posee dos letras, nuestras expresión regular pudiera condicionar 3 posibles casos.

regex = '^(el|El|EL)'    

Si aplicamos la expresión todo debería funcionar bien.

>>> pattern = re.compile(regex)
>>> pattern.search('El ejercicio de PyWombat')
<re.Match object; span=(0, 2), match='El'>

Pero, ¿Qué pasa si debemos validar sobre una palabra o frase mucho más extensa? Pues bien, en esos casos podemos agregar una opción a nuestro grupo. Por ejemplo, validemos que el string comience con la frase: Había una vez sin importar mayúsculas, minúsculas o ambas.

>>> regex = r'^(?i)Había una vez'                                                                 
>>> pattern = re.compile(regex)                                                                   
>>> pattern.search('había UNA veZ en un reino muy muy lejano...')                                 

<re.Match object; span=(0, 13), match='había UNA veZ'>

(?i) Case insensitive

Non-Capturing Groups

Habrá ocasiones en las cuales deseemos utilizar grupos, pero sin la necesidad de almacenarlos en memoria. A esto lo vamos a conocer cómo: Non-capturing groups. Y para ello debemos utilizar la siguiente expresión (?:pattern). Veamos un ejemplo.

>>> regex = r'Nuevo post en (?:PyWombat|pywombat)'
>>> pattern = re.compile(regex) 
>>> match = pattern.search('Nuevo post en PyWombat') 

>>> match.groups()                                                                                
()

Estoy es muy útil cuando solo deseamos validar el string y no deseamos trabajar con ningún grupo, mejorando así el performance de nuestras aplicaciones, evitando reservar espacio en memoria de forma innecesaria. 🎉


¿El contenido te resulto de ayuda?

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