2009-08-25 19 views
30

Tengo un archivo de texto que se parece a esto:Insertar línea en la posición especificada de un archivo de texto

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

Ahora quiero insertar 'foo bar' entre 'foo1 bar3' y 'foo2 bar4'.

Esto es cómo lo hice:

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) 

Esto funciona para mí, pero se ve bastante feo.

Respuesta

55

La mejor manera de hacer cambios "pseudo-in-situ" a un archivo en Python es con el módulo fileinput de la librería estándar:

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, 

También puede especificar una extensión de copia de seguridad si desea mantener el versión antigua, pero funciona de la misma manera que su código: usa .bak como la extensión de copia de seguridad, pero también la elimina una vez que el cambio se ha completado correctamente.

Además de utilizar el módulo de la biblioteca estándar de la derecha, este código utiliza la lógica más simple: para insertar una línea "foo bar" después de cada ejecución de las líneas que comienzan con foo1, un valor lógico es todo lo que necesita (soy yo dentro de un plazo tales o no?) Y El bool en cuestión se puede establecer incondicionalmente solo en función de si la línea actual comienza de esa manera o no. Si la lógica precisa que desea es ligeramente diferente de esta (que es lo que deduje de su código), no debería ser difícil modificar este código en consecuencia.

9

Recuerda que un iterador es un objeto de primera clase. Se puede usar en múltiples para declaraciones.

Aquí hay una manera de manejar esto sin un montón de declaraciones y banderas de aspecto complejo.

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

Gracias por el totalmente diferente enfoque. –

13

Adaptar el ejemplo de Alex Martelli:

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