2011-01-24 14 views
10

Estoy tratando de reemplazar texto en un archivo de texto leyendo cada línea, probándola y escribiendo si es necesario actualizarla. NO QUIERO guardar como un archivo nuevo, ya que mi secuencia de comandos ya realiza una copia de seguridad de los archivos primero y opera en las copias de seguridad.cómo reemplazar (actualizar) el texto en un archivo línea por línea

Esto es lo que tengo hasta ahora ... tengo fpath de os.walk() y garantizo que el pathmatch var devuelve correctamente:

fpath = os.path.join(thisdir, filename) 
with open(fpath, 'r+') as f: 
    for line in f.readlines(): 
     if '<a href="' in line: 
      for test in filelist: 
       pathmatch = file_match(line, test) 
        if pathmatch is not None: 
         repstring = filelist[test] + pathmatch 
         print 'old line:', line 
         line = line.replace(test, repstring) 
         print 'new line:', line 
         f.write(line) 

Pero lo que termina sucediendo es que solo me dan unas pocas líneas (actualizadas correctamente, fíjate, pero repetidas anteriormente en el archivo) corregidas. Creo que esto es un problema de alcance, un problema.

* También: me gustaría saber cómo reemplazar solo el texto en la primera instancia de la coincidencia, por ejemplo, no quiero hacer coincidir el texto de la pantalla, solo el href subyacente.

+1

¿ha considerado simplemente poniendo 'sed' en su lugar? – Amber

+0

http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 –

+0

@Amber: De muchas maneras. Realmente quiero terminar esto y aprender más tarde. Ya casi termino con esto ... :) – jml

Respuesta

9

Primero, desea escribir la línea, ya sea que coincida con el patrón o no. De lo contrario, estás escribiendo solo las líneas coincidentes.

En segundo lugar, entre leer las líneas y escribir los resultados, deberá truncar el archivo (puede f.seek(0) y luego f.truncate()), o cerrar el original y volver a abrir. Recogiendo el primero, que iba a terminar con algo como:

fpath = os.path.join(thisdir, filename) 
with open(fpath, 'r+') as f: 
    lines = f.readlines() 
    f.seek(0) 
    f.truncate() 
    for line in lines: 
     if '<a href="' in line: 
      for test in filelist: 
       pathmatch = file_match(line, test) 
        if pathmatch is not None: 
         repstring = filelist[test] + pathmatch 
         line = line.replace(test, repstring) 
     f.write(line) 
+0

muy útil ... gracias toneladas. Una cosa rara es que parecía "casi" funcionar la primera vez y luego lo ejecuté de nuevo y no reemplaza ninguno ... ¿algún pensamiento? Puedo intentar rastrearlo ... – jml

+0

No importa ... encontré cuál era el problema. ¡¡muchas gracias!! – jml

+0

hola otra vez raph: he modificado mi pregunta un poco. ¿Sería tan amable de explicarme cómo actualizar el código para permitir este tipo de reemplazo de un solo partido? gracias ... – jml

9
  1. Abra el archivo para leer y copiar todas las líneas en la memoria. Cierra el archivo.
  2. Aplica tus transformaciones en las líneas de la memoria.
  3. Abra el archivo para escribir y escribir todas las líneas de texto en la memoria.

with open(filename, "r") as f: 
    lines = (line.rstrip() for line in f) 
    altered_lines = [some_func(line) if regex.match(line) else line for line in lines] 
with open(filename, "w") as f: 
    f.write('\n'.join(altered_lines) + '\n') 
+0

gracias por la sugerencia alt hugh, pero creo que me gusta más la primera solución en términos de que coincida con mi intento. – jml

1

A (relativamente) de forma segura para reemplazar una línea en un archivo.

#!/usr/bin/python 
# defensive programming style 
# function to replace a line in a file 
# and not destroy data in case of error 

def replace_line(filepath, oldline, newline): 
    """ 
    replace a line in a temporary file, 
    then copy it over into the 
    original file if everything goes well 

    """ 

# quick parameter checks 
    assert os.exists(filepath)   # ! 
    assert (oldline and str(oldline)) # is not empty and is a string 
    assert (newline and str(newline)) 

    replaced = False 
    written = False 

    try: 

    with open(filepath, 'r+') as f: # open for read/write -- alias to f  

     lines = f.readlines()   # get all lines in file 

     if oldline not in lines: 
      pass       # line not found in file, do nothing 

     else: 
     tmpfile = NamedTemporaryFile(delete=True) # temp file opened for writing 

     for line in lines:   # process each line 
      if line == oldline:  # find the line we want 
      tmpfile.write(newline) # replace it 
      replaced = True 
      else: 
      tmpfile.write(oldline) # write old line unchanged 

     if replaced:     # overwrite the original file  
      f.seek(0)     # beginning of file 
      f.truncate()     # empties out original file 

      for tmplines in tmpfile: 
      f.write(tmplines)   # writes each line to original file 
      written = True 

     tmpfile.close()    # tmpfile auto deleted  
     f.close()       # we opened it , we close it 

    except IOError, ioe:     # if something bad happened. 
    printf ("ERROR" , ioe) 
    f.close()       
    return False 

    return replaced and written  # replacement happened with no errors = True 

(nota: esto reemplaza líneas enteras solamente, y todas las líneas que coinciden en el archivo)

Cuestiones relacionadas