tutorial regular online google escape course python regex performance file

regular - regex tutorial python



¿Cómo rebusco o re emparejo en un archivo completo sin leer todo en la memoria? (7)

Abra el archivo e itere sobre las líneas.

fd = open(''myfile'') for line in fd: if re.match(...,line) print line

Quiero poder ejecutar una expresión regular en un archivo completo, pero me gustaría poder no tener que leer todo el archivo en la memoria al mismo tiempo ya que puedo estar trabajando con archivos bastante grandes en el futuro. ¿Hay alguna forma de hacer esto? ¡Gracias!

Aclaración: no puedo leer línea por línea porque puede abarcar varias líneas.


Esto depende del archivo y la expresión regular. Lo mejor que podría hacer sería leer el archivo en línea por línea, pero si eso no funciona para su situación, entonces podría quedarse atascado con todo el archivo en la memoria.

Digamos, por ejemplo, que este es su archivo:

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut fringilla pede blandit eros sagittis viverra. Curabitur facilisis urna ABC elementum lacus molestie aliquet. Vestibulum lobortis semper risus. Etiam sollicitudin. Vivamus posuere mauris eu nulla. Nunc nisi. Curabitur fringilla fringilla elit. Nullam feugiat, metus et suscipit fermentum, mauris ipsum blandit purus, non vehicula purus felis sit amet tortor. Vestibulum odio. Mauris dapibus ultricies metus. Cras XYZ eu lectus. Cras elit turpis, ultrices nec, commodo eu, sodales non, erat. Quisque accumsan, nunc nec porttitor vulputate, erat dolor suscipit quam, a tristique justo turpis at erat.

Y esta era tu expresión regular:

consectetur(?=/sadipiscing)

Ahora esta expresión regular usa una búsqueda anticipada positiva y solo coincidirá con una cadena de "consectetur" si es seguida inmediatamente por cualquier carácter en blanco y luego una cadena de "adipiscing".

Por lo tanto, en este ejemplo, debería leer todo el archivo en la memoria porque su expresión regular depende del archivo completo que se analiza como una sola cadena. Este es uno de los muchos ejemplos que requieren que tenga toda su cadena en la memoria para que funcione una expresión regular en particular.

Supongo que la desafortunada respuesta es que todo depende de tu situación.


Para patrones de una sola línea puede iterar sobre las líneas del archivo, pero para patrones de varias líneas, tendrá que leer todo (o parte, pero será difícil hacer un seguimiento) del archivo en la memoria.


Puede usar mmap para asignar el archivo a la memoria. El contenido del archivo se puede acceder como una cadena normal:

import re, mmap with open(''/var/log/error.log'', ''r+'') as f: data = mmap.mmap(f.fileno(), 0) mo = re.search(''error: (.*)'', data) if mo: print "found error", mo.group(1)

Esto también funciona para archivos grandes, el contenido del archivo se carga internamente desde el disco según sea necesario.


Si esto es un gran problema y vale la pena un esfuerzo, puede convertir la expresión regular en una máquina de estado finito que lea el archivo. El FSM puede ser de complejidad O (n) lo que significa que será mucho más rápido a medida que el tamaño del archivo se agrande.

Podrá hacer coincidir de manera eficiente patrones que abarquen líneas en archivos demasiado grandes para caber en la memoria.

Aquí hay dos lugares que describen el algoritmo para convertir una expresión regular en un FSM:


Esta es una forma:

import re REGEX = ''/d+'' with open(''/tmp/workfile'', ''r'') as f: for line in f: print re.match(REGEX,line)

  1. con el operador en python 2.5 tomas de cierre automático de archivos. Por lo tanto, no necesita preocuparse por eso.
  2. el iterador sobre el objeto del archivo es eficiente desde el punto de vista de la memoria. es decir, no leerá más que una línea de memoria en un momento dado.
  3. Pero el inconveniente de este enfoque es que tomaría mucho tiempo para archivos de gran tamaño.

Otro enfoque que me viene a la mente es usar el método de lectura (tamaño) y file.seek (offset), que leerá una porción del tamaño del archivo a la vez.

import re REGEX = ''/d+'' with open(''/tmp/workfile'', ''r'') as f: filesize = f.size() part = filesize / 10 # a suitable size that you can determine ahead or in the prog. position = 0 while position <= filesize: content = f.read(part) print re.match(REGEX,content) position = position + part f.seek(position)

También puede combinar estos dos allí, puede crear un generador que devuelva un cierto contenido de bytes en el momento e iterar a través de ese contenido para verificar su expresión regular. Este IMO sería un buen enfoque.


f = open(filename,''r'') for eachline in f: string=re.search("(<tr align=/"right/"><td>)([0-9]*)(</td><td>)([a-zA-Z]*)(</td><td>)([a-zA-Z]*)(</td>)",eachline) if string: for i in range (2,8,2): add = string.group(i) l.append(add)