Odpowiedzi:
Najpierw otwórz plik i pobierz wszystkie swoje wiersze z pliku. Następnie ponownie otwórz plik w trybie zapisu i zapisz swoje wiersze z powrotem, z wyjątkiem wiersza, który chcesz usunąć:
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)
Potrzebujesz strip("\n")
znaku nowej linii w porównaniu, ponieważ jeśli twój plik nie kończy się znakiem nowej linii, ostatni też line
nie.
Rozwiązanie tego problemu przy tylko jednym otwarciu:
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()
To rozwiązanie otwiera plik w trybie r / w ("r +") i używa funkcji seek do zresetowania wskaźnika f, a następnie obcięcia, aby usunąć wszystko po ostatnim zapisie.
for
pętli, otrzymasz częściowo nadpisany plik z zduplikowanymi wierszami lub obciętą do połowy linią. Zamiast tego możesz chcieć f.truncate()
zaraz potem f.seek(0)
. W ten sposób, jeśli pojawi się błąd, skończysz z niekompletnym plikiem. Ale prawdziwym rozwiązaniem (jeśli masz miejsce na dysku) jest wyjście do pliku tymczasowego, a następnie użycie os.replace()
lub pathlib.Path(temp_filename).replace(original_filename)
zamiana go z oryginałem, gdy wszystko się powiedzie.
i.strip('\n') != "line you want to remove..."
jak wspomniano w zaakceptowanej odpowiedzi, że to doskonale rozwiązałoby mój problem. Ponieważ po prostu i
nic dla mnie nie zrobiłem
Najlepszą i najszybszą opcją, zamiast przechowywać wszystko na liście i ponownie otwierać plik, aby go zapisać, jest moim zdaniem ponowne zapisanie pliku w innym miejscu.
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)
Otóż to! W jednej pętli i tylko jednej możesz zrobić to samo. Będzie dużo szybciej.
(output.write(line) for line in input if line!="nickname_to_delete"+"\n")
subprocess.call(['mv', 'newfile.txt', 'yourfile.txt'])
os.replace
(nowość w Pythonie w wersji 3.3) jest bardziej wieloplatformowa niż wywołanie systemowe mv
.
To jest „widelec” od @Lother (którą moim zdaniem należy uznać za właściwą).
W przypadku takiego pliku:
$ cat file.txt
1: october rust
2: november rain
3: december snow
Ten widelec z rozwiązania Lother's działa dobrze:
#!/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()
Ulepszenia:
with open
, które odrzucają użycie f.close()
if/else
do oceny, czy w bieżącej linii nie ma łańcuchaProblem z czytaniem wierszy w pierwszym przebiegu i wprowadzaniem zmian (usuwanie określonych wierszy) w drugim przebiegu polega na tym, że jeśli rozmiary plików są ogromne, zabraknie pamięci RAM. Zamiast tego lepszym podejściem jest czytanie wierszy jeden po drugim i zapisywanie ich w osobnym pliku, eliminując te, których nie potrzebujesz. Uruchomiłem to podejście z plikami o wielkości do 12-50 GB, a użycie pamięci RAM pozostaje prawie stałe. Tylko cykle procesora pokazują przetwarzanie w toku.
Podobało mi się podejście do wpisywania plików, jak wyjaśniono w tej odpowiedzi: Usuwanie linii z pliku tekstowego (python)
Załóżmy na przykład, że mam plik, który ma puste wiersze i chcę usunąć puste wiersze, oto jak to rozwiązałem:
import fileinput
import sys
for line_number, line in enumerate(fileinput.input('file1.txt', inplace=1)):
if len(line) > 1:
sys.stdout.write(line)
Uwaga: puste wiersze w moim przypadku miały długość 1
Jeśli używasz Linuksa, możesz wypróbować następujące podejście.
Załóżmy, że masz plik tekstowy o nazwie animal.txt
:
$ cat animal.txt
dog
pig
cat
monkey
elephant
Usuń pierwszą linię:
>>> import subprocess
>>> subprocess.call(['sed','-i','/.*dog.*/d','animal.txt'])
następnie
$ cat animal.txt
pig
cat
monkey
elephant
Myślę, że jeśli wczytasz plik do listy, zrób to, co możesz iterować po liście, aby znaleźć pseudonim, którego chcesz się pozbyć. Możesz to zrobić znacznie wydajnie bez tworzenia dodatkowych plików, ale będziesz musiał zapisać wynik z powrotem do pliku źródłowego.
Oto jak mogę to zrobić:
import, os, csv # and other imports you need
nicknames_to_delete = ['Nick', 'Stephen', 'Mark']
Zakładam, że nicknames.csv
zawiera dane takie jak:
Nick
Maria
James
Chris
Mario
Stephen
Isabella
Ahmed
Julia
Mark
...
Następnie załaduj plik na listę:
nicknames = None
with open("nicknames.csv") as sourceFile:
nicknames = sourceFile.read().splitlines()
Następnie przejdź do listy, aby dopasować dane wejściowe do usunięcia:
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
Na koniec zapisz wynik z powrotem do pliku:
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()
Ogólnie nie możesz; musisz ponownie napisać cały plik (przynajmniej od momentu zmiany do końca).
W niektórych przypadkach możesz zrobić lepiej niż to -
jeśli wszystkie elementy danych mają taką samą długość i nie są ułożone w określonej kolejności, a znasz przesunięcie elementu, którego chcesz się pozbyć, możesz skopiować ostatni element do elementu, który ma zostać usunięty i skrócić plik przed ostatnim elementem ;
lub możesz po prostu nadpisać fragment danych wartością „to są złe dane, pomiń” lub zachować flagę „ten element został usunięty” w zapisanych elementach danych, tak aby można było oznaczyć go jako usuniętego bez konieczności modyfikowania pliku w inny sposób.
To prawdopodobnie przesada w przypadku krótkich dokumentów (mniej niż 100 KB?).
Prawdopodobnie masz już poprawną odpowiedź, ale oto moja. Zamiast używać listy do zbierania niefiltrowanych danych (jaka readlines()
metoda to robi), używam dwóch plików. Jedna służy do przechowywania głównych danych, a druga do filtrowania danych podczas usuwania określonego ciągu. Oto 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()
Mam nadzieję, że okaże się to przydatne! :)
Zapisz wiersze pliku na liście, a następnie usuń z listy wiersz, który chcesz usunąć i zapisz pozostałe wiersze do nowego pliku
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)
oto inna metoda usuwania / niektórych linii z pliku:
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()
Możesz skorzystać z
re
biblioteki
Zakładając, że jesteś w stanie załadować pełny plik txt. Następnie definiujesz listę niechcianych pseudonimów, a następnie zastępujesz je pustym ciągiem znaków „”.
# 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)
Aby usunąć określoną linię pliku według jej numeru linii :
Zastąp zmienne nazwa_pliku i line_to_delete nazwą twojego pliku i numerem linii, którą chcesz usunąć.
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))
Przykładowe dane wyjściowe :
Deleted line: 3
for nb, line in enumerate(f.readlines())
Weź zawartość pliku, podziel go znakiem nowej linii na krotkę. Następnie uzyskaj dostęp do numeru wiersza swojej krotki, dołącz do swojej krotki wyników i nadpisz do pliku.
tuple(f.read().split('\n'))
?? (2) „Uzyskaj dostęp do numeru wiersza swojej krotki” i „dołącz do swojej krotki wyników” brzmią raczej tajemniczo; rzeczywisty kod Pythona może być bardziej zrozumiały.
fileinput
jak opisał @ jf-sebastian tutaj . Wydaje się, że pozwala na pracę wiersz po wierszu, za pośrednictwem pliku tymczasowego, wszystko z prostąfor
składnią.