dosyadaki belirli bir satırı silmek için Python kullanma


145

Diyelim ki takma adlarla dolu bir metin dosyam var. Python kullanarak bu dosyadan belirli bir takma adı nasıl silebilirim?


1
fileinput@ Jf-sebastian tarafından burada açıklandığı gibi deneyin . Geçici bir dosya aracılığıyla, hepsi basit bir forsözdizimiyle satır satır çalışmanıza izin veriyor gibi görünüyor .
Kevin

Yanıtlar:


205

Önce dosyayı açın ve tüm satırlarınızı dosyadan alın. Ardından dosyayı yazma modunda yeniden açın ve silmek istediğiniz satır hariç satırlarınızı geri yazın:

with open("yourfile.txt", "r") as f:
    lines = f.readlines()
with open("yourfile.txt", "w") as f:
    for line in lines:
        if line.strip("\n") != "nickname_to_delete":
            f.write(line)

strip("\n")Karşılaştırmada yeni satır karakterine ihtiyacınız vardır, çünkü dosyanız yeni satır karakteri ile bitmezse son satır da sonlandırılmaz line.


2
neden iki kez açıp kapatmamız gerekiyor?
Ooker

3
@Ooker: Dosyayı iki kez açmanız (ve aralarında kapatmanız gerekir) çünkü ilk modda sadece salt okunurdur çünkü dosyadaki geçerli satırları okuyorsunuzdur. Daha sonra dosyayı kapatın ve dosyanın yazılabilir olduğu "yazma modunda" açın ve dosyanın içeriğini kaldırmak istediğiniz satırı sans.
Devin

4
Python bunu tek bir satırda yapmamıza neden izin vermiyor?
Ooker

5
@Ooker, Bir çizgi okuduğunuzda, imlecin okunduğu sırada çizgi boyunca hareket ettiğini hayal etmeye çalışın. Bu satır okunduktan sonra imleç şimdi geçiyor. Dosyaya yazmaya çalıştığınızda imlecin bulunduğu yere yazıyorsunuz. Dosyayı tekrar açarak imleci sıfırlarsınız.
Waddas

4
Bileşik ile kullanın!
Sceluswe

101

Sadece tek bir açık ile bu soruna çözüm:

with open("target.txt", "r+") as f:
    d = f.readlines()
    f.seek(0)
    for i in d:
        if i != "line you want to remove...":
            f.write(i)
    f.truncate()

Bu çözüm, dosyayı r / w modunda ("r +") açar ve f-işaretçisini sıfırlamak için aramadan yararlanır, ardından son yazma işleminden sonra her şeyi kaldırmak için keser.


2
Lockfile (fcntl) kullanmak zorunda olduğu gibi, bu benim için çok iyi çalıştı. Ben fcntl ile birlikte fileinput kullanmak için herhangi bir yol bulamadık.
Easyrider

1
Bu çözümün bazı yan etkilerini görmek güzel olurdu.
user1767754

3
Bunu yapmam. Döngüde bir hata foralırsanız, yinelenen satırlar veya yarı kesilmiş bir satırla kısmen üzerine yazılmış bir dosya elde edersiniz. Bunun f.truncate()hemen ardından bunu yapmak isteyebilirsiniz f.seek(0). Bu şekilde bir hata alırsanız, eksik bir dosya elde edersiniz. Ancak asıl çözüm (disk alanınız varsa) geçici bir dosyaya çıktı vermek ve her şey başarılı olduktan sonra orijinal ile değiştirmek os.replace()veya kullanmaktır pathlib.Path(temp_filename).replace(original_filename).
Boris

i.strip('\n') != "line you want to remove..."Benim sorunumu mükemmel bir şekilde çözecek kabul edilen cevapta belirtildiği gibi ekleyebilirsin . Çünkü ibenim için hiçbir şey yapmadı
Mangohero1

32

Her şeyi bir listede saklamak ve dosyayı yazmak için yeniden açmak yerine en iyi ve en hızlı seçenek, bence dosyayı başka bir yere yeniden yazmaktır.

with open("yourfile.txt", "r") as input:
    with open("newfile.txt", "w") as output: 
        for line in input:
            if line.strip("\n") != "nickname_to_delete":
                output.write(line)

Bu kadar! Bir döngüde ve sadece bir şeyi aynı şeyi yapabilirsiniz. Çok daha hızlı olacak.


Normal for döngüsü kullanmak yerine Jeneratör İfadesini kullanabiliriz. Bu şekilde program, dosyadan belleğe tüm satırları yüklemez, bu da büyük dosyalar için iyi bir fikir değildir. Bellekte aynı anda yalnızca tek bir satır olacaktır. Döngü için jeneratör ifadesi gibi görünecek,(output.write(line) for line in input if line!="nickname_to_delete"+"\n")
shrishinde

4
@ShriShinde Dosya nesnesi üzerinde döngü yaparken de dosyayı belleğe okumuyorsunuz, bu nedenle bu çözüm önerinizle aynı şekilde çalışıyor.
Steinar Lima

Orijinal dosyayı silmek ve ikinci dosyayı bir Linux işletim sisteminde Python ile aşağıdaki gibi görünecek orijinal dosyanın adıyla yeniden adlandırmak isteyebilirsiniz,subprocess.call(['mv', 'newfile.txt', 'yourfile.txt'])
Max

6
os.replace(python v 3.3'te yeni) bir sistem çağrısından daha çapraz platformdur mv.
7yl4r

Basit ve harika.
JuBaer AD

27

Bu @Lother cevabından bir "çatal" (ki bu doğru cevap olarak kabul edilmelidir inanıyorum).


Bunun gibi bir dosya için:

$ cat file.txt 
1: october rust
2: november rain
3: december snow

Lother'un çözümündeki bu çatal iyi çalışıyor:

#!/usr/bin/python3.4

with open("file.txt","r+") as f:
    new_f = f.readlines()
    f.seek(0)
    for line in new_f:
        if "snow" not in line:
            f.write(line)
    f.truncate()

İyileştirmeler:

  • with open, hangi f.close()
  • if/elsegeçerli satırda dize yoksa değerlendirme için daha net

F.seek (0) gerekiyorsa?
yifan

@ yifan evet. Aksi takdirde, dosyanın üzerine yazmak yerine dosyayı kendisine eklersiniz (hariç tuttuğunuz satırlar olmadan).
Boris

5

İlk geçişte satır okuma ve ikinci geçişte değişiklik yapma (belirli satırları silme) ile ilgili sorun, dosya boyutları çok büyükse, RAM'inizin bitmesi olacaktır. Bunun yerine, daha iyi bir yaklaşım satırları tek tek okumak ve ihtiyacınız olmayanları ortadan kaldırarak ayrı bir dosyaya yazmaktır. Bu yaklaşımı 12-50 GB kadar büyük dosyalarla çalıştırdım ve RAM kullanımı neredeyse sabit kalıyor. Yalnızca CPU döngüleri işlemin devam ettiğini gösterir.


2

Bu cevapta açıklandığı gibi fileinput yaklaşımını beğendim: Bir metin dosyasından (python) bir satırı silme

Diyelim ki içinde boş satırlar olan bir dosya var ve boş satırları kaldırmak istiyorum, işte nasıl çözdüm:

import fileinput
import sys
for line_number, line in enumerate(fileinput.input('file1.txt', inplace=1)):
    if len(line) > 1:
            sys.stdout.write(line)

Not: Benim durumumdaki boş satırların uzunluğu 1 idi


2

Linux kullanıyorsanız, aşağıdaki yaklaşımı deneyebilirsiniz.
Bir metin dosyanız olduğunu varsayalım animal.txt:

$ cat animal.txt  
dog
pig
cat 
monkey         
elephant  

İlk satırı silin:

>>> import subprocess
>>> subprocess.call(['sed','-i','/.*dog.*/d','animal.txt']) 

sonra

$ cat animal.txt
pig
cat
monkey
elephant

7
Bu çözüm işletim sistemi agnostik değildir ve OP bir işletim sistemi belirtmediğinden, Linux'a özel bir cevap imo'yu yayınlamak için bir neden yoktur.
Steinar Lima

2
Sadece python ile yapılabilecek herhangi bir şey için alt işlem kullanmayı öneren herkes bir aşağı not alır! Ve +1SteinarLima'ya +1 ... Katılıyorum
Jamie Lindsey

2

Dosyayı bir liste halinde okursanız, kurtulmak istediğiniz takma adı aramak için listeyi tekrarlayabilirsiniz. Ek dosyalar oluşturmadan çok verimli bir şekilde yapabilirsiniz, ancak sonucu kaynak dosyaya geri yazmanız gerekir.

Bunu nasıl yapabilirim:

import, os, csv # and other imports you need
nicknames_to_delete = ['Nick', 'Stephen', 'Mark']

Şöyle nicknames.csvveri içerdiğini varsayıyorum :

Nick
Maria
James
Chris
Mario
Stephen
Isabella
Ahmed
Julia
Mark
...

Ardından dosyayı listeye yükleyin:

 nicknames = None
 with open("nicknames.csv") as sourceFile:
     nicknames = sourceFile.read().splitlines()

Ardından, silinecek girişlerinizle eşleştirmek için listeyi tekrarlayın:

for nick in nicknames_to_delete:
     try:
         if nick in nicknames:
             nicknames.pop(nicknames.index(nick))
         else:
             print(nick + " is not found in the file")
     except ValueError:
         pass

Son olarak, sonucu dosyaya geri yazın:

with open("nicknames.csv", "a") as nicknamesFile:
    nicknamesFile.seek(0)
    nicknamesFile.truncate()
    nicknamesWriter = csv.writer(nicknamesFile)
    for name in nicknames:
        nicknamesWriter.writeRow([str(name)])
nicknamesFile.close()

1

Genel olarak yapamazsınız; tüm dosyayı tekrar yazmalısınız (en azından değişiklik noktasından sonuna kadar).

Bazı özel durumlarda bundan daha iyisini yapabilirsiniz -

tüm veri öğeleriniz aynı uzunlukta ve belirli bir sırada değilse ve kurtulmak istediğiniz öğenin ofsetini biliyorsanız, son öğeyi silinecek öğenin üzerine kopyalayabilir ve dosyayı son öğeden önce kısaltabilirsiniz ;

ya da veri yığınının üzerine 'bu kötü veri, atla' değeri yazabilir ya da kaydedilmiş veri öğelerinizde 'bu öğe silindi' bayrağını tutarak dosyayı değiştirmeden silinmiş olarak işaretleyebilirsiniz.

Bu kısa belgeler (100 KB'ın altında herhangi bir şey?)


1

Muhtemelen, zaten doğru bir cevabın var, ama işte benim. Filtrelenmemiş verileri toplamak için bir liste kullanmak yerine (hangi readlines()yöntem yapar), iki dosya kullanıyorum. Birincisi ana verileri tutmak, ikincisi belirli bir dizeyi sildiğinizde verileri filtrelemek içindir. İşte bir kod:

main_file = open('data_base.txt').read()    # your main dataBase file
filter_file = open('filter_base.txt', 'w')
filter_file.write(main_file)
filter_file.close()
main_file = open('data_base.txt', 'w')
for line in open('filter_base'):
    if 'your data to delete' not in line:    # remove a specific string
        main_file.write(line)                # put all strings back to your db except deleted
    else: pass
main_file.close()

Umarım bu yararlı bulacaksınız! :)


0

Dosya satırlarını bir listeye kaydedin, ardından silmek istediğiniz satırı listeden kaldırın ve kalan satırları yeni bir dosyaya yazın

with open("file_name.txt", "r") as f:
    lines = f.readlines() 
    lines.remove("Line you want to delete\n")
    with open("new_file.txt", "w") as new_f:
        for line in lines:        
            new_f.write(line)

Bir cevap verirken cevabınızın NEDEN olduğu hakkında bazı açıklamalar yapmak tercih edilir .
Stephen Rauch

Dosyanız yeni satırla bitmezse, kaldırmak istediğiniz bir sözcük olsa bile bu kod son satırı kaldırmaz.
Boris

0

a / some satır (lar) ını bir dosyadan kaldırmanın başka bir yöntemi:

src_file = zzzz.txt
f = open(src_file, "r")
contents = f.readlines()
f.close()

contents.pop(idx) # remove the line item from list, by line number, starts from 0

f = open(src_file, "w")
contents = "".join(contents)
f.write(contents)
f.close()

0

Ben fileinput ve 'inplace' yöntemini kullanarak bu yöntemi seviyorum:

import fileinput
for line in fileinput.input(fname, inplace =1):
    line = line.strip()
    if not 'UnwantedWord' in line:
        print(line)

Diğer cevaplardan biraz daha az endişeli ve


0

reKütüphaneyi kullanabilirsiniz

Tam txt dosyanızı yükleyebileceğinizi varsayarsak. Daha sonra istenmeyen takma adların bir listesini tanımlar ve ardından bunları "" boş bir dize ile değiştirirsiniz.

# Delete unwanted characters
import re

# Read, then decode for py2 compat.
path_to_file = 'data/nicknames.txt'
text = open(path_to_file, 'rb').read().decode(encoding='utf-8')

# Define unwanted nicknames and substitute them
unwanted_nickname_list = ['SourDough']
text = re.sub("|".join(unwanted_nickname_list), "", text)

-1

Dosyanın belirli bir satırını satır numarasına göre silmek için :

Dosya adı ve line_to_delete değişkenlerini dosyanızın adı ve silmek istediğiniz satır numarası ile değiştirin.

filename = 'foo.txt'
line_to_delete = 3
initial_line = 1
file_lines = {}

with open(filename) as f:
    content = f.readlines() 

for line in content:
    file_lines[initial_line] = line.strip()
    initial_line += 1

f = open(filename, "w")
for line_number, line_content in file_lines.items():
    if line_number != line_to_delete:
        f.write('{}\n'.format(line_content))

f.close()
print('Deleted line: {}'.format(line_to_delete))

Örnek çıktı :

Deleted line: 3

bir for nb, line in enumerate(f.readlines())
diksiyon inşa etmeye

-3

Dosyanın içeriğini alın, satırsonuna göre bir demet halinde bölün. Ardından, grubunuzun satır numarasına erişin, sonuç grubunuza katılın ve dosyanın üzerine yazın.


6
(1) Bunu mu demek istediniz tuple(f.read().split('\n'))? (2) "grubunuzun satır numarasına erişin" ve "sonuç grubunuza katılın" sesi oldukça gizemli; gerçek Python kodu daha anlaşılır olabilir.
John Machin
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.