2009-08-25 4 views
30

Ho un file di testo che assomiglia a questo:Inserimento riga all'altezza della posizione specificata di un file di testo

blah blah 
foo1 bar1 
foo1 bar2 
foo1 bar3 
foo2 bar4 
foo2 bar5 
blah blah 

Ora voglio inserire 'foo bar' tra 'foo1 bar3' e 'foo2 bar4'.

Ecco come ho fatto:

import shutil 

txt = '1.txt' 
tmptxt = '1.txt.tmp' 

with open(tmptxt, 'w') as outfile: 
    with open(txt, 'r') as infile: 
     flag = 0 
     for line in infile: 
      if not line.startswith('foo1') and flag == 0: 
       outfile.write(line) 
       continue 
      if line.startswith('foo1') and flag == 0: 
       flag = 1 
       outfile.write(line) 
       continue 
      if line.startswith('foo1') and flag == 1: 
       outfile.write(line) 
       continue 
      if not line.startswith('foo1') and flag == 1: 
       outfile.write('foo bar\n') 
       outfile.write(line) 
       flag = 2 
       continue 
      if not line.startswith('foo1') and flag == 2: 
       outfile.write(line) 
       continue 

shutil.move(tmptxt, txt) 

questo funziona per me, ma sembra piuttosto brutto.

risposta

55

Il modo migliore per rendere "pseudo-inplace" cambia in un file in Python è con il modulo fileinput dalla libreria standard:

import fileinput 

processing_foo1s = False 

for line in fileinput.input('1.txt', inplace=1): 
    if line.startswith('foo1'): 
    processing_foo1s = True 
    else: 
    if processing_foo1s: 
     print 'foo bar' 
    processing_foo1s = False 
    print line, 

è anche possibile specificare un'estensione di backup se si desidera mantenere la vecchia versione, ma funziona allo stesso modo del codice: usa .bak come estensione di backup ma la rimuove anche una volta completata la modifica.

Oltre a utilizzare il diritto modulo di libreria standard, questo codice utilizza la logica più semplice: per inserire una linea "foo bar" dopo ogni serie di linee che iniziano con foo1, un valore booleano è tutto ciò che serve (sono io dentro una tale corsa o no?) E il bool in questione può essere impostato incondizionatamente solo in base al fatto che la linea corrente inizi in quel modo o meno. Se la logica precisa che desideri è leggermente diversa da questa (che è ciò che ho dedotto dal tuo codice), non dovrebbe essere difficile modificare questo codice di conseguenza.

9

Ricordare che un iteratore è un oggetto di prima classe. Può essere utilizzato in più per le dichiarazioni.

Ecco un modo per gestire questo problema senza un sacco di istruzioni if ​​e di bandiere dall'aspetto complesso.

with open(tmptxt, 'w') as outfile: 
    with open(txt, 'r') as infile: 
     rowIter= iter(infile) 
     for row in rowIter: 
      if row.startswith('foo2'): # Start of next section 
       break 
      print row.rstrip(), repr(row) 
     print "foo bar" 
     print row 
     for row in rowIter: 
      print row.rstrip() 
+0

Grazie per l'approccio totalmente diverso. –

13

Adattamento esempio di Alex Martelli:

import fileinput 
for line in fileinput.input('1.txt', inplace=1): 
print line, 
if line.startswith('foo1 bar3'): 
    print 'foo bar' 
Problemi correlati