2009-11-27 14 views
7

Supponiamo di aprire un file e di eseguire una ricerca() da qualche parte nel file, come si conosce la riga del file corrente?Come ottenere la linea di file aperta corrente in python?

(Ho risolto personalmente con una classe di file ad-hoc che associa la posizione di ricerca alla riga dopo la scansione del file, ma volevo vedere altri suggerimenti e aggiungere questa domanda a StackOverflow, poiché non ero in grado di trovare il problema ovunque su google)

+0

In realtà ho pubblicato la classe da qualche parte qui su SO ... non so dove. –

+1

Se si sta cercando un offset di byte, non c'è modo di conoscere la linea # senza contare il # di \ n caratteri incontrati prima di quella posizione. Per quanto riguarda il modo più efficiente con un file, non ne sono sicuro .... Buona fortuna! – gahooa

+0

sì. forse c'è qualche libreria che fa questo servizio. L'ho implementato personalmente come ho detto, ma preferirei delegare questa attività a una libreria esterna, se possibile. –

risposta

4

Ecco come vorrei affrontare il problema, utilizzando il più pigrizia possibile:

from random import randint 
from itertools import takewhile, islice 

file = "/etc/passwd" 
f = open(file, "r") 

f.seek(randint(10,250)) 
pos = f.tell() 

print "pos=%d" % pos 

def countbytes(iterable): 
    bytes = 0 
    for item in iterable: 
     bytes += len(item) 
     yield bytes 

print 1+len(list(takewhile(lambda x: x <= pos, countbytes(open(file, "r"))))) 

Per un approccio un po 'meno leggibile ma molto più pigri, utilizzare enumerate e dropwhile:

from random import randint 
from itertools import islice, dropwhile 

file = "/etc/passwd" 
f = open(file, "r") 

f.seek(randint(10,250)) 
pos = f.tell() 

print "pos=%d" % pos 

def countbytes(iterable): 
    bytes = 0 
    for item in iterable: 
     bytes += len(item) 
     yield bytes 

print list(
     islice(
      dropwhile(lambda x: x[1] <= pos, enumerate(countbytes(open(file, "r")))) 
      , 1))[0][0]+1 
+0

uso freddo di itertools ... :) –

6

Quando si utilizza seek(), python utilizza gli offset del puntatore per passare alla posizione desiderata nel file. Ma per conoscere il numero di linea corrente, devi esaminare ciascun personaggio fino a quella posizione. Quindi, si potrebbe anche abbandonare seek() a favore di read():

Sostituire

f = open(filename, "r") 
f.seek(55) 

con

f = open(filename, "r") 
line=f.read(55).count('\n')+1 
print(line) 

Forse non si desidera utilizzare f.read (num) dal questo potrebbe richiedere molta memoria se num è molto grande. In tal caso, è possibile utilizzare un generatore di come questo:

import itertools 
import operator 
line_number=reduce(operator.add,(f.read(1)=='\n' for _ in itertools.repeat(None,num))) 
pos=f.tell() 

Ciò equivale a f.seek(num) con l'ulteriore vantaggio di dare line_number.