аватар question@mail.ru · 01.01.1970 03:00

Каким образом удалить строчки выборочно?

Есть некий файл, состоящий из строк. Нужно удалить выборочно строки, начинающиеся с определенного набора символов при помощи python. Как это сделать?

Вот пример

ATOM 14ATOM 15ANISOU 15ATOM 16ANISOU 16

нужно удалить все, что начинается с ANISOU

аватар answer@mail.ru · 01.01.1970 03:00

Как удалить каждую вторую строку из файла на python?

, чтобы прозрачно создать временный файл, чтобы по месту изменения выполнить:

#!/usr/bin/env python3import fileinputimport oswith fileinput.FileInput(filename, inplace=True, backup='.bak') as file:    for i, line in enumerate(file, start=1):        if i & 1: # odd             print(line, end='') # keep line (stdout is redirected to the file)os.unlink(filename + '.bak') # remove the backup on success

Этот for-цикл можно также записать, :

import sysfrom itertools import islicesys.stdout.writelines(islice(file, 0, None, 2))  # keep lines[::2]

Если реализация .writelines() не пишет строки по мере поступления, а загружает их всех в память, то можно использовать явный for-цикл, чтобы по одной строке писать, не загружая весь файл в память.

Для небольшого файла полный код может использовать .readlines(), чтобы получить список строк (загрузить файл в память) и целиком перезаписать этот файл, рискуя потерять данные если ошибка возникнет:

with open(filename) as file:    lines = file.readlines()[::2] # lines to keepwith open(filename, 'w') as file:    file.writelines(lines)

Для небольшого файла, заданного с командной строки или стандартного ввода (stdin), пренебрегая возможными ошибками, :

#!/usr/bin/env python3import fileinputfrom itertools import isliceprint("""".join(islice(fileinput.input(), 0, None, 2)), end='')

это полный скрипт. Использование:

$ every-other-line file1 file2 >output_file

В более общем случае, чтобы удалить строки по месту из файла, не создавая временный файл и не загружая всё содержимое в память, , но вероятно менее эффективное решение создают:

from itertools import islicewith open(filename, 'r+') as file:    write_offset = file.tell() # where to write next    for line in islice(iter(file.readline, ''), 0, None, 2):  # keep lines[::2]        read_offset = file.tell() # where to read next        file.seek(write_offset)        file.write(line)        write_offset = file.tell()        file.seek(read_offset)    file.truncate(write_offset)

Этот более сложный вариант работает и для файлов, которые как в оперативную память не помещаются так и для которых нет места, чтобы копию на диске создать.

нужно удалить все, что начинается с ANISOU

Можно адаптировать приведённые выше примеры кода:

import fileinputimport oswith fileinput.FileInput(filename, inplace=True, backup='.bak') as file:    for line in file:        if not line.startswith('ANISOU'):             print(line, end='') # keep line (stdout is redirected to the file)os.unlink(filename + '.bak') # remove the backup on success

Можно (к примеру, если в текущей директории не достаточно места для копии файла, можно явно другую директорию указать (на другом диске) и использовать , если необходимо):

#!/usr/bin/env python3from pathlib import Pathfrom tempfile import NamedTemporaryFilepath = Path(filename)with path.open() as file, \     NamedTemporaryFile('w', dir=str(path.parent), delete=False) as output_file:      for line in file:         if not line.startswith('ANISOU'):              print(line, end='', file=output_file)Path(output_file.name).replace(path)

Загрузив строки в память:

with open(filename) as file:    lines = [line for line in file if not line.startswith('ANISOU')]with open(filename, 'w') as file:    file.writelines(lines)

Легко адаптировать к другим условиям, определив keep_line() предикат, к примеру:

with open(filename) as file:    lines = list(filter(keep_line, file))with open(filename, 'w') as file:    file.writelines(lines)

где в данном случае:

def keep_line(line):    retu not line.startswith('ANISOU')

Последние

Похожие