Let\'s say I have a text file containing:
Dan
Warrior
500
1
0
Is there a way I can edit a specific line in that text file? Right now I have this:
#!/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()
Yes, I know that myfile.writelines(\'Mage\')[1]
is incorrect. But you get my point, right? I\'m trying to edit line 2 by replacing Warrior with Mage. But can I even do that?
You want to do something like this:
# 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 )
The reason for this is that you can\'t do something like \"change line 2\" directly in a file. You can only overwrite (not delete) parts of a file - that means that the new content just covers the old content. So, if you wrote \'Mage\' over line 2, the resulting line would be \'Mageior\'.
you can use fileinput to do in place editing
import fileinput
for line in fileinput.FileInput(\"myfile\", inplace=1):
if line .....:
print line
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()
And then:
replace_line(\'stats.txt\', 0, \'Mage\')
If your text contains only one individual:
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()
If your text contains several individuals:
import 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()
If the “job“ of an individual was of a constant length in the texte, you could change only the portion of texte corresponding to the “job“ the desired individual:
that’s the same idea as senderle’s one.
But according to me, better would be to put the characteristics of individuals in a dictionnary recorded in file with 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
You can do it in two ways, choose what suits your requirement:
Method I.) Replacing using line number. You can use built-in function enumerate()
in this case:
First, in read mode get all data in a variable
with open(\"your_file.txt\",\'r\') as f:
get_all=f.readlines()
Second, write to the file (where enumerate comes to action)
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)
Method II.) Using the keyword you want to replace:
Open file in read mode and copy the contents to a list
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\" has been replaced by \"Mage\", so write the updated data to the file:
with open(\"some_file.txt\",\"w\") as f:
for line in newline:
f.writelines(line)
This is what the output will be in both cases:
Dan Dan
Warrior ------> Mage
500 500
1 1
0 0
I have been practising working on files this evening and realised that I can build on Jochen\'s answer to provide greater functionality for repeated/multiple use. Unfortunately my answer does not address issue of dealing with large files but does make life easier in smaller files.
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))