2011-08-17 11 views
10

Tengo un archivo de texto con el siguiente formato:repetidamente extraer una línea entre dos delimitadores en un archivo de texto, Python

DELIMITER1 
extract me 
extract me 
extract me 
DELIMITER2 

me gustaría extraer cada bloque de extract me s entre DELIMITER1 y en el DELIMITER2 archivo .txt

Ésta es mi actual código de realización no,:

import re 
def GetTheSentences(file): 
    fileContents = open(file) 
    start_rx = re.compile('DELIMITER') 
    end_rx = re.compile('DELIMITER2') 

    line_iterator = iter(fileContents) 
    start = False 
    for line in line_iterator: 
      if re.findall(start_rx, line): 

       start = True 
       break 
     while start: 
      next_line = next(line_iterator) 
      if re.findall(end_rx, next_line): 
       break 

      print next_line 

      continue 
     line_iterator.next() 

¿Alguna idea?

Respuesta

16

puede simplificar esto a una expresión regular usando re.S, la DOTALL flag.

import re 
def GetTheSentences(infile): 
    with open(infile) as fp: 
     for result in re.findall('DELIMITER1(.*?)DELIMITER2', fp.read(), re.S): 
      print result 
# extract me 
# extract me 
# extract me 

Esto también hace uso del operador no expansivo .*?, por lo que varios bloques que no se solapan de pares DELIMITER1-DELIMITER2 se pueden encontrar.

+3

consejo: utilice esto con un objeto de archivo mapeado en memoria (a través del módulo 'mmap') si su archivo es demasiado grande para leerlo todo a la vez. – Steven

+0

@Brent Probé esto y funciona muy bien ... ¡Gracias! – Renklauf

+0

Me alegro de poder ayudar. No olvide marcar una respuesta como aceptada si es la mejor respuesta a su pregunta. –

2

Esto debería hacer lo que quiera:

import re 
def GetTheSentences(file): 
    start_rx = re.compile('DELIMITER') 
    end_rx = re.compile('DELIMITER2') 

    start = False 
    output = [] 
    with open(file, 'rb') as datafile: 
     for line in datafile.readlines(): 
      if re.match(start_rx, line): 
       start = True 
      elif re.match(end_rx, line): 
       start = False 
      if start: 
        output.append(line) 
    return output 

Su versión anterior parece que se supone que es una función de iterador. ¿Desea que su resultado sea devuelto un artículo a la vez? Eso es un poco diferente.

+0

No es necesario leer todo el archivo en la memoria. Tampoco necesita expresiones regulares si se trata de algo tan simple como encontrar una subcadena específica en una línea. – agf

+0

@agf Por supuesto que no, pero su ejemplo simplista puede no corresponder exactamente con sus datos. He hecho algo muy similar a un archivo de postscript, y absolutamente tenía que tener expresiones regulares para mis puntos de inicio y fin. –

+0

@todas las gracias por toda la ayuda en esto! – Renklauf

2

Si los delimitadores están dentro de una línea:

def get_sentences(filename): 
    with open(filename) as file_contents: 
     d1, d2 = '.', ',' # just example delimiters 
     for line in file_contents: 
      i1, i2 = line.find(d1), line.find(d2) 
      if -1 < i1 < i2: 
       yield line[i1+1:i2] 


sentences = list(get_sentences('path/to/my/file')) 

Si están en sus propias líneas:

def get_sentences(filename): 
    with open(filename) as file_contents: 
     d1, d2 = '.', ',' # just example delimiters 
     results = [] 
     for line in file_contents: 
      if d1 in line: 
       results = [] 
      elif d2 in line: 
       yield results 
      else: 
       results.append(line) 

sentences = list(get_sentences('path/to/my/file')) 
+0

Rastreo (llamada más reciente pasado): Archivo "", línea 1, en Archivo "", línea 10, en get_sentences UnboundLocalError: variable local ' resultados referenciados antes de la asignación – amadain

+0

@amadain Agregué una línea para inicializar los resultados, pero al ver esto no estoy seguro de que sea correcto de todos modos. – agf

0

Este es un buen trabajo para la comprensión de listas, no se requiere regex. Primero, la lista borra la típica \n en la lista de líneas de texto encontrada al abrir el archivo txt. La segunda lista de comp solo usa el operador in para identificar patrones de secuencia para filtrar.

def extract_lines(file): 
    scrubbed = [x.strip('\n') for x in open(file, 'r')] 
    return [x for x in scrubbed if x not in ('DELIMITER1','DELIMITER2')] 
Cuestiones relacionadas