การแก้ไขบรรทัดเฉพาะในไฟล์ข้อความใน Python


88

สมมติว่าฉันมีไฟล์ข้อความที่ประกอบด้วย:

Dan
Warrior
500
1
0

มีวิธีแก้ไขบรรทัดเฉพาะในไฟล์ข้อความนั้นได้อย่างไร ตอนนี้ฉันมีสิ่งนี้:

#!/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()

ใช่ฉันรู้ว่าmyfile.writelines('Mage')[1]ไม่ถูกต้อง แต่คุณเข้าใจฉันใช่มั้ย? ฉันกำลังพยายามแก้ไขบรรทัดที่ 2 โดยแทนที่ Warrior ด้วย Mage แต่ฉันสามารถทำได้หรือไม่?


1
ฉันคิดว่าโพสต์นี้ครอบคลุมสิ่งที่คุณกำลังมองหา: stackoverflow.com/questions/1998233/…
Kyle Wild

1
หากคุณต้องทำสิ่งนี้เป็นจำนวนมากคุณอาจต้องการดูการแปลงไฟล์นี้จากข้อความเป็น bdb หรือ bdb อื่น ๆ
Nick Bastin

คำตอบ:


125

คุณต้องการทำสิ่งนี้:

# 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 )

สาเหตุคือคุณไม่สามารถทำบางอย่างเช่น "เปลี่ยนบรรทัด 2" ในไฟล์ได้โดยตรง คุณสามารถเขียนทับ (ไม่ลบ) บางส่วนของไฟล์เท่านั้นซึ่งหมายความว่าเนื้อหาใหม่จะครอบคลุมเนื้อหาเก่าเท่านั้น ดังนั้นถ้าคุณเขียน 'Mage' เหนือบรรทัดที่ 2 บรรทัดผลลัพธ์จะเป็น 'Mageior'


2
สวัสดี Jochen คำสั่ง "with open (filename, mode)" ยังปิดชื่อไฟล์โดยปริยายหลังจากโปรแกรมออกใช่ไหม?
Radu

@ Gabriel Thx นั่นเป็นสิ่งสำคัญที่ต้องทราบแม้ว่าฉันจะยังไม่ได้ใช้กับ ... Pythonic หรือไม่ฉันไม่ชอบ :)
Radu

@Radu มันเป็นเรื่องของความเคยชิน ฉันยังเคยปิดไฟล์ที่เปิดด้วยตนเองด้วยclose.แต่ตอนนี้ฉันเห็นว่าการใช้withบล็อกนั้นสะอาดกว่ามาก
Gabriel

5
ถือว่าถูกต้องหรือไม่นี่เป็นวิธีแก้ปัญหาที่ต้องการสำหรับไฟล์ขนาดเล็ก มิฉะนั้นเราอาจต้องใช้หน่วยความจำจำนวนมากเพื่อจัดเก็บข้อมูล ยิ่งไปกว่านั้นแม้จะแก้ไข 1 ครั้งเราก็ต้องเขียนสิ่งทั้งหมดอีกครั้ง
Arindam Roychowdhury

11
แย่ .. ถ้าคุณมีไฟล์ 20 Gb ล่ะ?
Brans Ds


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()

แล้ว:

replace_line('stats.txt', 0, 'Mage')

9
สิ่งนี้จะโหลดเนื้อหาของไฟล์ทั้งหมดลงในหน่วยความจำซึ่งอาจไม่ใช่เรื่องดีหากไฟล์มีขนาดใหญ่
Steve Ng

@SteveNg คุณมีวิธีแก้ปัญหาที่คุณสังเกตเห็นหรือไม่? ทั้งคำตอบนี้และคำตอบที่ยอมรับนั้นอาศัยการโหลดไฟล์ทั้งหมดในหน่วยความจำ
Blupon

14

คุณสามารถทำได้สองวิธีเลือกสิ่งที่เหมาะกับความต้องการของคุณ:

วิธีที่ 1)แทนที่โดยใช้หมายเลขบรรทัด คุณสามารถใช้ฟังก์ชันenumerate()ในตัวได้ในกรณีนี้:

ขั้นแรกในโหมดอ่านรับข้อมูลทั้งหมดในตัวแปร

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

ประการที่สองเขียนลงในไฟล์ (ที่ซึ่งการระบุมาถึงการดำเนินการ)

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)

วิธีที่ II.)โดยใช้คีย์เวิร์ดที่คุณต้องการแทนที่:

เปิดไฟล์ในโหมดอ่านและคัดลอกเนื้อหาไปยังรายการ

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" ถูกแทนที่ด้วย "Mage" ดังนั้นเขียนข้อมูลที่อัปเดตลงในไฟล์:

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

นี่คือสิ่งที่ผลลัพธ์จะเป็นในทั้งสองกรณี:

Dan                   Dan           
Warrior   ------>     Mage       
500                   500           
1                     1   
0                     0           

3

หากข้อความของคุณมีเพียงคนเดียว:

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()

หากข้อความของคุณมีบุคคลหลายคน:

นำเข้าใหม่

# 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()

หาก "งาน" ของแต่ละบุคคลมีความยาวคงที่ในข้อความคุณสามารถเปลี่ยนเฉพาะส่วนของข้อความที่ตรงกับ "งาน" ที่ต้องการซึ่งเป็นแนวคิดเดียวกับงานของผู้ส่ง

แต่ตามที่ฉันพูดดีกว่าคือการใส่ลักษณะของบุคคลในพจนานุกรมที่บันทึกไว้ในไฟล์ด้วย 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

2

เมื่อเย็นนี้ฉันได้ฝึกฝนการทำงานกับไฟล์และตระหนักว่าฉันสามารถสร้างคำตอบของ Jochen เพื่อมอบฟังก์ชันการทำงานที่ดียิ่งขึ้นสำหรับการใช้งานซ้ำ / หลายครั้ง น่าเสียดายที่คำตอบของฉันไม่ได้กล่าวถึงปัญหาในการจัดการกับไฟล์ขนาดใหญ่ แต่ทำให้ชีวิตง่ายขึ้นในไฟล์ขนาดเล็ก

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))

0

นี่เป็นวิธีที่ง่ายที่สุดในการทำเช่นนี้

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

ฉันหวังว่ามันจะได้ผลสำหรับคุณ


-1
#read file lines and edit specific item

file=open("pythonmydemo.txt",'r')
a=file.readlines()
print(a[0][6:11])

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

file=open("pythonmydemo.txt",'w')
file.writelines(a)
file.close()
print(a)

1
ยินดีต้อนรับสู่ Stack Overflow! โปรดทราบว่าคุณกำลังตอบคำถามที่เก่ามากและได้รับคำตอบแล้ว นี่เป็นคำแนะนำเกี่ยวกับวิธีการตอบ
help-info.de

@ ajay-jaiswal โปรดระบุคำถามของคุณและให้ตัวอย่างที่ทำซ้ำได้น้อยที่สุดและข้อความแสดงข้อผิดพลาดที่คุณได้รับ คุณโพสต์รหัส แต่ไม่ใช่คำถามจริง
dmitryro

-2

สมมติว่าฉันมีไฟล์ชื่อfile_nameดังต่อไปนี้:

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

เราต้องแทนที่บรรทัดที่ 2 ด้วย "แก้ไขเสร็จแล้ว":

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.