Extrayendo datos usando expresiones regulares

Si queremos extraer datos de una cadena en Python podemos usar el método findall() para extraer todas las subcadenas que coincidan con una expresión regular. Usemos el ejemplo de querer extraer cualquier secuencia que parezca una dirección email en cualquier línea, sin importar su formato. Por ejemplo, queremos extraer la dirección email de cada una de las siguientes líneas:

No queremos escribir código para cada tipo de líneas, dividiendo y rebanando de manera distinta en cada una. El siguiente programa usa findall() para encontrar las líneas que contienen direcciones de email y extraer una o más direcciones de cada línea.

El método findall() busca en la cadena en el segundo argumento y retorna una lista de todas las cadenas que parecen ser direcciones de email. Estamos usando una secuencia de dos caracteres que coincide con un carácter distinto a un espacio en blanco (\S).

El resultado de la ejecución del programa debiera ser:

Traduciendo la expresión regular al castellano, estamos buscando subcadenas que tengan al menos un carácter que no sea un espacio, seguido de una @, seguido de al menos un carácter que no sea un espacio. La expresión \S+ coincidirá con cuantos caracteres distintos de un espacio sea posible.

La expresión regular retornaría dos coincidencias (csev@umich.edu y cwen@iupui.edu), pero no coincidiría con la cadena “@2PM” porque no hay caracteres que no sean espacios en blanco antes del signo @. Podemos usar esta expresión regular en un programa para leer todas las líneas en un archivo e imprimir cualquier subcadena que pudiera ser una dirección de email de la siguiente manera:

Con esto, leemos cada línea y luego extraemos las subcadenas que coincidan con nuestra expresión regular. Dado que findall() retorna una lista, simplemente revisamos si el número de elementos en ésta es mayor a cero e imprimir solo líneas donde encontramos al menos una subcadena que pudiera ser una dirección de email. Si ejecutamos el programa en con el archivo mbox.txt obtendremos el siguiente resultado:

Algunas de las direcciones tienen caracteres incorrectos como “<” o “;” al comienzo o al final. Declaremos que solo estamos interesados en la parte de la cadena que comience y termine con una letra o un número.

Para lograr esto, usamos otra característica de las expresiones regulares. Los
corchetes se usan para indicar un conjunto de caracteres que queremos aceptar
como coincidencias. La secuencia \S retornará el conjunto de “caracteres que no
sean un espacio en blanco
”. Ahora seremos un poco más explícitos en cuanto a los caracteres respecto de los cuales buscamos coincidencias.

Esta será nuestra nueva expresión regular:

Esto se está complicando un poco; puedes ver por qué decimos que las expresiones regulares son un lenguaje en sí mismas. Traduciendo esta expresión regular, estamos buscando subcadenas que comiencen con una letra minúscula, letra mayúscula, o número “[a-zA-Z0-9]”, seguida de cero o más caracteres que no sean un espacio (\S), seguidos de un signo @, seguido de cero o más caracteres que no sean espacios en blanco (\S), seguidos por una letra mayúscula o minúscula. Nótese que hemos cambiado de + a * para indicar cero o más caracteres que no sean espacios, ya que [a-zA-Z0-9] implica un carácter distinto de un espacio. Recuerda que el + se aplica al carácter inmediatamente a la izquierda del signo de suma o del asterisco.

Nótese que en las líneas donde aparece source@collab.sakaiproject.org, nuestra expresión regular eliminó dos caracteres al final de la cadena (“>;”). Esto
se debe a que, cuando agregamos [a-zA-Z] al final de nuestra expresión regular,
estamos determinando que cualquier cadena que la expresión regular encuentre al analizar el texto debe terminar con una letra. Por lo tanto, cuando vea el “>
al final de “sakaiproject.org>;”, simplemente se detiene en el último carácter que haya encontrado que coincida con ese criterio (en este caso, la “g” fue la última coincidencia).

Vemos también que el resultado de la ejecución del programa es una lista de Python que tiene una cadena como su único elemento.