2011-09-26 26 views
12

No estoy hablando de números de línea específicos porque estoy leyendo varios archivos con el mismo formato, pero varían en longitud.
decir que tengo este archivo de texto:python - Leer archivo desde y hacia líneas de texto específicas

Something here... 
... ... ... 
Start      #I want this block of text 
a b c d e f g 
h i j k l m n 
End      #until this line of the file 
something here... 
... ... ... 

espero que sepas lo que quiero decir. Estaba pensando en iterar a través del archivo y luego buscar usando expresiones regulares para encontrar el número de línea de "Inicio" y "Finalizar", luego uso el caché de línea para leer desde la línea de inicio hasta la línea de finalización. ¿Pero cómo obtener el número de línea? ¿Qué función puedo usar?

+0

Esta pregunta es muy similar a éste http://stackoverflow.com/questions/7098530/repeatedly-extract-a-line-between-two-delimiters-in-a-text-file-python – salomonvh

Respuesta

21

Si simplemente desea que el bloque de texto entre principio y fin, se puede hacer algo tan simple como:

with open('test.txt') as input_data: 
    # Skips text before the beginning of the interesting block: 
    for line in input_data: 
     if line.strip() == 'Start': # Or whatever test is needed 
      break 
    # Reads text until the end of the block: 
    for line in input_data: # This keeps reading the file 
     if line.strip() == 'End': 
      break 
     print line # Line is extracted (or block_of_lines.append(line), etc.) 

De hecho, usted no necesita manipular los números de línea con el fin de leer los datos entre los marcadores de Inicio y Fin.

La lógica ("leer hasta ...") se repite en ambos bloques, pero es bastante clara y eficiente (otros métodos generalmente implican verificar algún estado [antes del bloque/dentro del bloque/final del bloque alcanzado], que incurre en pena de tiempo).

1

Esto debería ser un comienzo para usted:

started = False 
collected_lines = [] 
with open(path, "r") as fp: 
    for i, line in enumerate(fp.readlines()): 
     if line.rstrip() == "Start": 
      started = True 
      print "started at line", i # counts from zero ! 
      continue 
      if started and line.rstrip()=="End": 
      print "end at line", i 
      break 
      # process line 
      collected_lines.append(line.rstrip()) 

El generador enumerate lleva un generador y enumera las iteraciones. Eg.

print list(enumerate("a b c".split())) 

impresiones

[ (0, "a"), (1,"b"), (2, "c") ] 

ACTUALIZACIÓN:

el cartel preguntó por usar una expresión regular para que coincida con líneas como "===" y "======":

import re 
print re.match("^=+$", "===")  is not None 
print re.match("^=+$", "======") is not None 
print re.match("^=+$", "=")  is not None 
print re.match("^=+$", "=abc") is not None 
print re.match("^=+$", "abc=") is not None 
3

Aquí hay algo que funcione:

data_file = open("test.txt") 
block = "" 
found = False 

for line in data_file: 
    if found: 
     block += line 
     if line.strip() == "End": break 
    else: 
     if line.strip() == "Start": 
      found = True 
      block = "Start" 

data_file.close() 
+0

este es un buen truco – BPm

+3

@BPm: Este es un ejemplo de una "máquina de estados finitos" (http://en.wikipedia.org/wiki/Finite_state_machine): la máquina se inicia en un estado "Bloque no encontrado aún" (encontrado == False), sigue ejecutándose en un estado "Dentro del bloque" (encontrado == True) y en este caso se detiene cuando se encuentra "End". Pueden ser un poco ineficientes (aquí, 'found' se debe verificar para cada línea en el bloque), pero las máquinas de estado a menudo permiten que uno exprese limpiamente la lógica de algoritmos más complejos. – EOL

+0

+1, porque este es un buen ejemplo del enfoque de máquina de estado completamente válido. – EOL

2

Puede usar una expresión regular con bastante facilidad. Puede hacerlo más robusto según sea necesario, a continuación se muestra un ejemplo simple.

>>> import re 
>>> START = "some" 
>>> END = "Hello" 
>>> test = "this is some\nsample text\nthat has the\nwords Hello World\n" 
>>> m = re.compile(r'%s.*?%s' % (START,END),re.S) 
>>> m.search(test).group(0) 
'some\nsample text\nthat has the\nwords Hello' 
+0

+1: Muy buena idea: es compacto y puede ser muy eficiente, ya que el módulo 're' es rápido. Sin embargo, las etiquetas START y END deberían forzarse a estar en una línea * por sí mismas *, en su expresión regular ('^ ... $'). – EOL

+0

Gracias:) .. No creo que puedas usar^|| $ cuando usas el re.S spec, ya que incluye caracteres nuevos, cree que debería decir explícitamente '% s \ n. *?% S \ n' – pyInTheSky

+1

Puede usar^... $ en este caso, simplemente agregando el indicador re.MULTILINE (http://docs.python.org/dev/library/re.html#module-contents). – EOL

Cuestiones relacionadas