¿Cómo tomo texto de un archivo de texto dentro de un límite de números de línea pitónicamente?

Estoy tratando de obtener datos del archivo de texto. Las líneas de interés en el archivo de texto son aquellas que coinciden con el 'Marcador 2' hasta la última instancia del 'Marcador 3'. Puede haber múltiples Marcadores (duplicados). Quería el número de línea mínimo del 'Marcador 2' y el número de línea máximo del 'Marcador 3': todo el texto dentro de ese mínimo/máximo. Mientras esto funciona, quiero ver cómo hacerlo de la manera pythonic, más eficiente y con menos código.

¿Por qué tuve que abrir el mismo archivo dos veces? Me estaba dando lo contrario, ¿xreadlines y readlines en conflicto?

file_seeklines.py

import sys

filename = sys.argv[1]

line_number = []
number = 0

## Fetch the boundary(start, end points)
f = open(filename,'r')

for line in f.xreadlines():
    number += 1
    if "marker 2" in line.strip().lower():
        line_number.append(number)
    if "marker 3" in line.strip().lower():    
        line_number.append(number)

#print line_number[0], line_number[-1]
start, end = line_number[0]-1, line_number[-1]

f.close()

## Grab the boundary 
g = open(filename,'r')

linelist = g.readlines()

try:
    for i in xrange(start, end):
        print linelist[i]
except:
    print "failed"
    pass
g.close()

archivo.txt

Welcome notice
------------------------
Hello there, welcome! Foo
Marker 0
hello

world

Bar
Yes!
Foo

How are ya?!

Bar

Have a great day!

Marker 1

Hello 1 2
12

MarKer 2
Hello 23
23
Marker 3
Hello 34
34

marker 2
Hello 45
45
MArker 3

salida

MarKer 2

Hello 23

23

Marker 3

Hello 34

34



marker 2

Hello 45

45

MArker 3

preguntado el 22 de mayo de 12 a las 17:05

Por cierto, el código escrito se lee desde la línea min que contiene marker 2 or marker 3 a la línea máxima que contiene marker 2 or marker 3. -

Mientras hace min o max, luego busco el límite de min/max de la lista. Quiero hacer una captura codiciosa de texto. -

3 Respuestas

Si su archivo no es demasiado grande para read() en la memoria, puede optar por un enfoque de expresiones regulares (aprovechando el hecho de que el * operador es codicioso):

import re
with open(filename, 'r') as f:
    inBetween = re.search(r"Marker 2(.*)Marker 3", f.read(), re.S | re.I).group()

Otra opción es recorrer las líneas en ambas direcciones, deteniéndose en la primera aparición de "Marcador 2" y Marcador 3", respectivamente:

with open(filename, 'r') as f:
    lines = f.readlines
    for i in range(len(lines)):
        if "marker 2" in lines[i].lower():
            start = i
            break
    else:
        start = None

    for i in range(len(lines), -1, -1):
        if "marker 3" in lines[i].lower():
            end = i
            break
    else:
        end = None

    if None not in (start, end):
        inBetween = lines[start + 1:end]
    else:
        #one of the markers is missing, handle here.

contestado el 22 de mayo de 12 a las 17:05

AttributeError: el objeto 'NoneType' no tiene atributo 'group' - no coincide con el patrón - pensar código

@ThinkCode: agrega la bandera re.IGNORECASE. - joel cornett

Probé con IGNORECASE, sin dados. Su otra solución es dar TypeError: el objeto de tipo 'builtin_function_or_method' no tiene error len(). - pensar código

@ThinkCode: No hay problema. Gracias por recordarme que pruebe mis respuestas antes de publicarlas :P - joel cornett

Esto lo hace no codicioso (.*?) si alguien está buscando una solución a mi pregunta: inBetween = re.search(r"Marker 2(.*?)Marker 3", f.read(), re.S | re.I).grupo() - pensar código

¿Hay alguna razón por la que no estés usando una expresión regular? es decir (marker 2.*marker 3) con re.DOTALL y re.IGNORECASE banderas.

contestado el 22 de mayo de 12 a las 17:05

No use readlines() pero read() para que no tenga que iterar sobre las líneas.

A continuación, puede encontrar la parte que le interesa con split().

P.ej

with open(filename,'r') as f:
    text = f.read().lower().split("marker 2",1)[1]
    text = text.rsplit("marker 3",1)[0]

    print('marker 2\n'+text+'marker 3')

contestado el 22 de mayo de 12 a las 17:05

Solo se está agarrando el último partido. No devolver el límite. - pensar código

Ahora me da el archivo de texto completo. - pensar código

Lo estoy pensando. Pero la pregunta pide solo una coincidencia, ¿verdad? - Junuxx

Debería ser f.read().split("marker 2", 1)[1].rsplit("marker 3", 1)[0] - joel cornett

No, el límite - (min, max). Min es la primera aparición del 'Marcador 2' y Max es la máxima aparición del 'Marcador 3'. - pensar código

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.