Editar una línea específica en un archivo de texto en Python

86

Digamos que tengo un archivo de texto que contiene:

Dan
Warrior
500
1
0

¿Hay alguna forma de que pueda editar una línea específica en ese archivo de texto? Ahora mismo tengo esto:

#!/usr/bin/env python
import io

myfile = open('stats.txt', 'r')
dan = myfile.readline()
print dan
print "Your name: " + dan.split('\n')[0]

try:
    myfile = open('stats.txt', 'a')
    myfile.writelines('Mage')[1]
except IOError:
        myfile.close()
finally:
        myfile.close()

Sí, sé que eso myfile.writelines('Mage')[1]es incorrecto. Pero entiendes mi punto, ¿verdad? Estoy tratando de editar la línea 2 reemplazando Warrior con Mage. Pero, ¿puedo siquiera hacer eso?

prueba
fuente
1
Creo que esta publicación cubre lo que estás buscando: stackoverflow.com/questions/1998233/…
Kyle Wild
1
Si tiene que hacer mucho este tipo de cosas, es posible que desee convertir este archivo de texto a algo como bdb u otro bdb similar.
Nick Bastin

Respuestas:

123

Quieres hacer algo como esto:

# with is like your try .. finally block in this case
with open('stats.txt', 'r') as file:
    # read a list of lines into data
    data = file.readlines()

print data
print "Your name: " + data[0]

# now change the 2nd line, note that you have to add a newline
data[1] = 'Mage\n'

# and write everything back
with open('stats.txt', 'w') as file:
    file.writelines( data )

La razón de esto es que no puede hacer algo como "cambiar la línea 2" directamente en un archivo. Solo puede sobrescribir (no eliminar) partes de un archivo; eso significa que el contenido nuevo solo cubre el contenido anterior. Entonces, si escribió 'Mage' sobre la línea 2, la línea resultante sería 'Mageior'.

Jochen Ritzel
fuente
2
Hola Jochen, la declaración "con abrir (nombre de archivo, modo)" también cierra el nombre de archivo implícitamente después de que el programa lo sale, ¿verdad?
Radu
@Gabriel Thx, es importante tenerlo en cuenta, aunque todavía no uso la declaración with ... as file. Pythonic o no, no me gusta :)
Radu
@Radu es cuestión de acostumbrarse. También solía cerrar los archivos abiertos manualmente a través de, close.pero ahora veo que usar un withbloque es mucho más limpio.
Gabriel
5
¿Es correcto asumir que esta es una solución preferida para archivos pequeños? De lo contrario, podríamos necesitar mucha memoria solo para almacenar los datos. Además, incluso para 1 edición, necesitamos escribir todo de nuevo.
Arindam Roychowdhury
11
Malo ... ¿y si tienes un archivo de 20 Gb?
Brans Ds
21

puede usar fileinput para editar en el lugar

import fileinput
for  line in fileinput.FileInput("myfile", inplace=1):
    if line .....:
         print line
ghostdog74
fuente
19
def replace_line(file_name, line_num, text):
    lines = open(file_name, 'r').readlines()
    lines[line_num] = text
    out = open(file_name, 'w')
    out.writelines(lines)
    out.close()

Y entonces:

replace_line('stats.txt', 0, 'Mage')
Peter C
fuente
9
esto cargaría todo el contenido del archivo en la memoria, lo que podría no ser bueno si el archivo es enorme.
Steve Ng
@SteveNg, ¿tiene una solución para el problema que notó? tanto esta respuesta como la aceptada se basan en cargar todo el archivo en la memoria
Blupon
13

Puede hacerlo de dos formas, elija la que se adapte a sus necesidades:

Método I.) Reemplazo usando el número de línea. Puede utilizar la función incorporadaenumerate() en este caso:

Primero, en modo lectura obtenga todos los datos en una variable

with open("your_file.txt",'r') as f:
    get_all=f.readlines()

En segundo lugar, escriba en el archivo (donde enumerate entra en acción)

with open("your_file.txt",'w') as f:
    for i,line in enumerate(get_all,1):         ## STARTS THE NUMBERING FROM 1 (by default it begins with 0)    
        if i == 2:                              ## OVERWRITES line:2
            f.writelines("Mage\n")
        else:
            f.writelines(line)

Método II.) Usando la palabra clave que desea reemplazar:

Abra el archivo en modo lectura y copie el contenido a una lista

with open("some_file.txt","r") as f:
    newline=[]
    for word in f.readlines():        
        newline.append(word.replace("Warrior","Mage"))  ## Replace the keyword while you copy.  

"Warrior" ha sido reemplazado por "Mage", así que escribe los datos actualizados en el archivo:

with open("some_file.txt","w") as f:
    for line in newline:
        f.writelines(line)

Esto es lo que será la salida en ambos casos:

Dan                   Dan           
Warrior   ------>     Mage       
500                   500           
1                     1   
0                     0           
Aseem Yadav
fuente
3

Si su texto contiene solo una persona:

import re

# creation
with open('pers.txt','wb') as g:
    g.write('Dan \n Warrior \n 500 \r\n 1 \r 0 ')

with open('pers.txt','rb') as h:
    print 'exact content of pers.txt before treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt before treatment:\n',h.read()


# treatment
def roplo(file_name,what):
    patR = re.compile('^([^\r\n]+[\r\n]+)[^\r\n]+')
    with open(file_name,'rb+') as f:
        ch = f.read()
        f.seek(0)
        f.write(patR.sub('\\1'+what,ch))
roplo('pers.txt','Mage')


# after treatment
with open('pers.txt','rb') as h:
    print '\nexact content of pers.txt after treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt after treatment:\n',h.read()

Si su texto contiene varias personas:

importar re

# creation
with open('pers.txt','wb') as g:
    g.write('Dan \n Warrior \n 500 \r\n 1 \r 0 \n Jim  \n  dragonfly\r300\r2\n10\r\nSomo\ncosmonaut\n490\r\n3\r65')

with open('pers.txt','rb') as h:
    print 'exact content of pers.txt before treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt before treatment:\n',h.read()


# treatment
def ripli(file_name,who,what):
    with open(file_name,'rb+') as f:
        ch = f.read()
        x,y = re.search('^\s*'+who+'\s*[\r\n]+([^\r\n]+)',ch,re.MULTILINE).span(1)
        f.seek(x)
        f.write(what+ch[y:])
ripli('pers.txt','Jim','Wizard')


# after treatment
with open('pers.txt','rb') as h:
    print 'exact content of pers.txt after treatment:\n',repr(h.read())
with open('pers.txt','rU') as h:
    print '\nrU-display of pers.txt after treatment:\n',h.read()

Si el "trabajo" de un individuo fuera de una longitud constante en el texto, podría cambiar solo la parte del texto correspondiente al "trabajo" del individuo deseado: esa es la misma idea que la del remitente.

Pero según yo, mejor sería poner las características de los individuos en un diccionario grabado en archivo con cPickle:

from cPickle import dump, load

with open('cards','wb') as f:
    dump({'Dan':['Warrior',500,1,0],'Jim':['dragonfly',300,2,10],'Somo':['cosmonaut',490,3,65]},f)

with open('cards','rb') as g:
    id_cards = load(g)
print 'id_cards before change==',id_cards

id_cards['Jim'][0] = 'Wizard'

with open('cards','w') as h:
    dump(id_cards,h)

with open('cards') as e:
    id_cards = load(e)
print '\nid_cards after change==',id_cards
eyquem
fuente
2

He estado practicando trabajar con archivos esta noche y me di cuenta de que puedo aprovechar la respuesta de Jochen para proporcionar una mayor funcionalidad para uso repetido / múltiple. Desafortunadamente, mi respuesta no aborda el problema de tratar con archivos grandes, pero facilita la vida en archivos más pequeños.

with open('filetochange.txt', 'r+') as foo:
    data = foo.readlines()                  #reads file as list
    pos = int(input("Which position in list to edit? "))-1  #list position to edit
    data.insert(pos, "more foo"+"\n")           #inserts before item to edit
    x = data[pos+1]
    data.remove(x)                      #removes item to edit
    foo.seek(0)                     #seeks beginning of file
    for i in data:
        i.strip()                   #strips "\n" from list items
        foo.write(str(i))
ellos no
fuente
0

Esta es la forma más sencilla de hacer esto.

fin = open("a.txt")
f = open("file.txt", "wt")
for line in fin:
    f.write( line.replace('foo', 'bar') )
fin.close()
f.close()

Espero que funcione para ti.

Rohit Nishad
fuente
-1

# leer líneas de archivo y editar un elemento específico

file = open ("pythonmydemo.txt", 'r')

a = archivo.readlines ()

imprimir (a [0] [6:11])

a [0] = a [0] [0: 5] + 'Ericsson \ n'

imprimir (a [0])

file = open ("pythonmydemo.txt", 'w')

file.writelines (a)

file.close ()

imprimir (a)

Ajay Jaiswal
fuente
1
¡Bienvenido a Stack Overflow! Tenga en cuenta que está respondiendo a una pregunta muy antigua y ya respondida. Aquí hay una guía sobre cómo responder .
help-info.de
-2

Supongamos que tengo un archivo file_namecon el siguiente nombre:

this is python
it is file handling
this is editing of line

Tenemos que reemplazar la línea 2 con "la modificación está lista":

f=open("file_name","r+")
a=f.readlines()
for line in f:
   if line.startswith("rai"):
      p=a.index(line)
#so now we have the position of the line which to be modified
a[p]="modification is done"
f.seek(0)
f.truncate() #ersing all data from the file
f.close()
#so now we have an empty file and we will write the modified content now in the file
o=open("file_name","w")
for i in a:
   o.write(i)
o.close()
#now the modification is done in the file
Shivam Rai
fuente