Tu blog de tutoriales Python en habla hispana

Expresiones Regulares

Las expresiones regulares son expresiones comodín que definen patrones de caracteres a emparejar y extraer de una cadena de texto. Para entenderlo con un ejemplo, definamos «Python» como nuestra expresión regular y «Programa en Python» como nuestra cadena de texto. En este caso, nuestra cadena de texto contiene una instancia de nuestra expresión regular. Si bien este ejemplo ilustrativo puede resultar sencillo, en este post veremos como las expresiones regulares se ayudan de caracteres especiales para poder emparejar cualquier patrón de texto, pudiendo llegar a considerarse un lenguaje en sí mismas. También cabe mencionar que las expresiones regulares no son una característica exclusiva de Python, ya que también están presentes en otros lenguajes de programación como Java, JavaScript, Ruby, entre otros.

Métodos para usar expresiones regulares en Python

El uso de las expresiones regulares en Python viene dado por el paquete re, que hay que importar a nuestro código. Algunos de los métodos proporcionados en este paquete son:

  • re.search(patrón, cadena): busca la primera ocurrencia de la expresión regular definida en patrón dentro del string cadena. El resultado se devuelve en un objeto Match en caso de que exista tal ocurrencia, o en un objeto None en caso contrario. Siguiendo con el ejemplo anterior:
>>> import re
>>> re.search("Python", "Programa en Python")
<re.Match object; span=(12, 18), match='Python'>
  • re.findall(patrón, cadena): devuelve una lista que contiene todas las ocurrencias de la expresión regular definida en patrón dentro del string cadena. Las ocurrencias se devuelven en el mismo orden en que se han encontrado.
>>> import re
>>> re.findall("Python", "Programa en Python es mi blog favorito de Python, y gracias a él me estoy convirtiendo en todo un Pythonista.")
['Python', 'Python', 'Python']
  • re.split(separador, cadena): divide la cadena tomando en cuenta las ocurrencias del separador. El resultado se devuelve en una lista.
>>> re.split("@","nombre.apellido@ejemplo.tld")
['nombre.apellido', 'ejemplo.tld']

Caracteres para definir expresiones regulares

Hasta ahora hemos visto ejemplos muy simples del uso de las expresiones regulares. En este apartado vamos a ver los distintos caracteres o comodínes que podemos utilizar para formar patrones de búsqueda más complejos.

Inicio y fin de línea: ^, $

Los símbolos de acento circunflejo (^) y dólar ($) indican que nuestro patrón de búsqueda debe contener respectivamente el inicio o fin de una línea en una cadena de texto. En el siguiente ejemplo, la expresión regular ‘^Python’ busca ocurrencias de la cadena Python al inicio de la línea, y por eso el método findall devuelve sólo una ocurrencia a pesar de que la frase contenga dos veces la cadena ‘Python’.

>>> import re
>>> frase = "Python no sólo es un lenguaje de programación, Python es mi lenguaje de programacón favorito."
>>> patron = '^Python'
>>> re.findall(patron, frase)
['Python']
>>> frase = "Me gusta aprender Python y programar en Python"
>>> patron = 'Python$'
>>> re.findall(patron, frase)
['Python']

Coincidencia de caracteres: ., \s, \S

Los símbolos ., \s y \S indican respectivamente cualquier carácter, espacio en blanco y cualquier carácter a excepción del espacio en blanco. En el siguiente ejemplo, ‘^.ython’ busca al principio de la línea (^) cualquier carácter (.) seguido por la cadena ‘ython’. Es decir, palabras como Aython, Bython, Cython, etc. a principio de línea se interpretan como una coincidencia. Sin embargo, la expresión regular ‘\s.ython’ empareja en la frase de ejemplo con ‘ Nython’ y ‘ Python’, ya que esta expresión regular busca un espacio en blanco al principio de la ocurrencia.

>>> import re
>>> frase = "Cython no es ningún lenguaje de programación y Nython tampoco pero Python sí"
>>> patron = '^.ython'
>>> palabras = re.findall(patron, frase)
['Cython']
>>> patron = '\\s.ython'
>>> palabras = re.findall(patron, frase)
[' Nython', ' Python']

Caracteres de repetición: *, +, ?

Estos tres caracteres tienen el siguiente significado:

  • * : indica la repetición de un carácter cero o más veces.
  • + : indica la repetición de un carácter una o más veces.
  • ? : Es el carácter reluctant o cuantificador reacio. Añadido a cualquiera de los anteriores se contará con la ocurrencia más corta posible.

El siguiente ejemplo ilustra el uso del cuantificador reacio. El primer patrón: ‘.+n’, busca cualquier repetición de caracteres que termine en ‘n’. Como la última palabra de la frase termina en ‘n’, el resultado de la búsqueda retorna la frase entera. Sin embargo, al añadir el cuantificador reacio al patrón: ‘.+?n’ el resultado de la búsqueda resulta más restrictiva ya que ésta contiene todas las secuencias de caracteres terminadas en ‘n’.

>>> import re
>>> frase = "Ramón y Román programan en Python"
>>> patron = '.+n'
>>> re.findall(patron, frase)
['Ramón y Román programan en Python']
>>> patron = '.+?n'
>>> re.findall(patron, frase)
['Ramón', ' y Román', ' programan', ' en', ' Python']

Conjunto de caracteres: [], [^]

Encerrando un conjunto de caracteres entre corchetes ([]) indica cualquiera de los caracteres especificados. Así, el patrón [abc] coincidiría con las secuencias ‘a’, ‘b’ o ‘c’. El siguiente ejemplo ilustra el uso de los corchetes. En él podemos ver que patrón ‘[CN]ython’ no encuentra coincidencia con la secuencia ‘Python’ de la frase, ya que ‘P’ no está dentro de los corchetes.

>>> import re
>>> frase = "Cython no es ningún lenguaje de programación y Nython tampoco pero Python sí"
>>> patron = '[CN]ython'
>>> re.findall(patron, frase)
['Cython', 'Nython']  

El acento circunflejo (^) al principio de la secuencia entre corchetes se utiliza para indicar negación. Es decir la no coincidencia con los caracteres especificados. Un ejemplo de uso puede ser la separación de las palabras de una frase excluyendo sus signos de puntuación.

>>> import re
>>> frase = "¡Esto es una frase! Además contiene signos de puntuación. ¿Los eliminamos?"
>>> patron = '[^¡!.¿? ]+'
>>> re.findall(patron, frase)
['Esto', 'es', 'una', 'frase', 'Además', 'contiene', 'signos', 'de', 'puntuación', 'Los', 'eliminamos']

Rangos de caracteres: [a-z]

Dentro de los conjuntos de caracteres también podemos especificar rangos añadiendo un guión a la secuencia. Algunos ejemplos de uso son los siguientes:

  • [a-z]+ : indica una secuencia de letras minúsculas.
  • [A-Z]+ : se usa para encontrar secuencias de letras mayúsculas.
  • [a-zA-Z]+ : es para secuencias de letras mayúsculas o minúsculas.
  • [A-Z][a-z]+ : secuencias de una letra mayúscula seguida de una o más letras mayúsculas.
  • [0-9]+ : para secuencias de números de uno o más dígitos.
>>> import re
>>> frase = "Tengo 2 hijos que tienen 15 y 11 años"
>>> patron = '[0-9]+'
>>> re.findall(patron, frase)
['2', '15', '11']

Inicio y fin de la extracción: ()

Los paréntesis ( ) no forman parte del patrón a comprobar, pero indican respectivamente dónde empieza y termina la extracción del texto. Un caso de uso es la extracción de dominios en direcciones de correo electrónico. Esta operación la podemos realizar mediante el patrón: ‘@([^ ]*)’ En este caso sabemos que el dominio viene después de un símbolo de arroba (@) que indicamos en nuestra expresión regular, seguido de una condición cerrada entre paréntesis ya que no queremos que el resultado contenga arrobas.

>>> import re
>>> frase = "Tengo dos correos electrónicos que son nombre.apellido@dominio.tld y nombre@dominio.com"
>>> patron = '@([^ ]*)'
>>> re.findall(patron, frase)
['dominio.tld', 'dominio.com']

Conclusión

En este post hemos visto cómo utilizar expresiones regulares para encontrar patrones de caracteres dentro de un texto. Las expresiones regulares si bien simplifican nuestro código también pueden llegar a ser muy complicadas. Si te encallas o no sabes porqué tus resultados no son los esperados, mi recomendación es que intentes buscar en google ya que probablemente en algún foro de programación alguien tenga la solución que necesitas.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

dos × 1 =