Thursday, August 13, 2009

Python: expresiones regulares

Para trabajar con expresiones regulares en python hay que importar el módulo re, que contiene:

import re

help(re)
....
This module exports the following functions:
match Match a regular expression pattern to the beginning of a string.
search Search a string for the presence of a pattern.
sub Substitute occurrences of a pattern found in a string.
subn Same as sub, but also return the number of substitutions made.
split Split a string by the occurrences of a pattern.
findall Find all occurrences of a pattern in a string.
finditer Return an iterator yielding a match object for each match.
compile Compile a pattern into a RegexObject.
purge Clear the regular expression cache.
escape Backslash all non-alphanumerics in a string.
....


Las búsquedas se pueden hacer compilando previamente el patrón o sin compilarlo.

Sin compilar:
#!/usr/bin/env python
import re

patron=";;(.*?);;"
texto="aquí el nombre ;;campo1;; y aquí los apellidos ;;campo2;;"

for campo in re.findall(patron,texto):
print "Coincidencia : ",campo


Compilando: (creando el objeto expresión regular)
#!/usr/bin/env python
import re

patron=re.compile(";;(.*?);;")
texto="aquí el nombre ;;campo1;; y aquí los apellidos ;;campo2;;"

for campo in patron.findall(texto):
print "Coincidencia : ",campo


La diferencia está en que con el segundo proceder creamos un objeto "expresión regular" que contendrá los métodos propios de una expresión regular. P.e. findall, search ... La segunda diferencia es que al llamar al método findall en el primer caso accedemos al módulo y en el segundo al método del objeto.

Sobre una única ejecución en un fichero medio no va mucha diferencia, aunque la hay. A continuación pongo un ejemplo en que sí la hay al abrir un fichero de log de 80000 líneas y hacer una búsqueda repetidamente.

Compilando: (creando el objeto expresión regular)



#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

def run_re():
pattern = "ass"
re_obj = re.compile(pattern)
infile = open ("/var/log/dpkg.log.1","r")

match_count = 0
lines = 0

for line in infile:
match = re_obj.search(line)
if match :
match_count += 1
lines += 1
return (lines , match_count)

if __name__=="__main__" :
lines,match_count = run_re()
print "Lines :: ",lines
print "Matches :: ",match_count


Sin crear el objeto expresión regular:


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import re

def run_re():
pattern = "ass"
infile = open ("/var/log/dpkg.log.1","r")

match_count = 0
lines = 0

for line in infile:
match = re.search(pattern,line)
if match :
match_count += 1
lines += 1

return (lines,match_count)

if __name__=='__main__' :
lines,match_count = run_re()
print "Lines :: ",lines
print "Matches :: ",match_count

3 comments:

Profeta said...

Oh Dios de las expresiones regulares.
Oh Dios de las máquinas virtuales y de los Oracles perdidos. Por fin te acuerdas de aquellos que te juramos fidelidad... Neng, yo creía que escribía poco, pero lo tuyo tiene delito! Ah, por cierto, para que querriamos usar Python en vez de Bash? o lo escrito es para añadirle la funcionalidad de las expresiones regulares al programa que programemos en dicho lenguaje?

sysadim guy said...

Buenas profeta,

cada cosa tiene sus ventajas. Lo cierto es que con python hay cosas que resultan mucho más fáciles. Además no hay Debian o similar que no la lleve instalada en una instalación básica.
Apuesto que lo mismo vale para RedHat/Fedora y Suse.

Siempre es un placer vernos por aquí ;)

Anonymous said...

El código Bash de la cabeza del programa es para indicarle al SO con que aplicación ha de ejecutar el script. =) saludos a todos!