Удаление указанного c количества строк из текстового файла с использованием Python - PullRequest
1 голос
/ 17 марта 2020

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

AAAAAAAAAAAAAAAAAAAAA              #<--- line 1
BBBBBBBBBBBBBBBBBBBBB              #<--- line 2
CCCCCCCCCCCCCCCCCCCCC              #<--- line 3
DDDDDDDDDDDDDDDDDDDDD              #<--- line 4
EEEEEEEEEEEEEEEEEEEEE              #<--- line 5
FFFFFFFFFFFFFFFFFFFFF              #<--- line 6
GGGGGGGGGGGGGGGGGGGGG              #<--- line 7
HHHHHHHHHHHHHHHHHHHHH              #<--- line 8


Игнорировать "# <--- line ...", это просто для демонстрации </em>


Допущения

  • Я не знаю, что будет содержать строка 3 (потому что она все время меняется) ...
  • Первые 2 строки необходимо удалить ...
  • После первых 2 строк я хочу сохранить 3 строки ...
  • Затем я хочу удалить все строки после 3-й строки.


Конечный результат
Конечный результат должен выглядеть следующим образом:

CCCCCCCCCCCCCCCCCCCCC              #<--- line 3
DDDDDDDDDDDDDDDDDDDDD              #<--- line 4
EEEEEEEEEEEEEEEEEEEEE              #<--- line 5


Строки удалены: Первые 2 + Все после следующих 3 (т.е. после строки 5)

Требуется
Все предложения Pythoni c приветствуются! Спасибо!




Справочный материал
https://thispointer.com/python-how-to-delete-specific-lines-in-a-file-in-a-memory-efficient-way/

def delete_multiple_lines(original_file, line_numbers):
    """In a file, delete the lines at line number in given list"""
    is_skipped = False
    counter = 0
    # Create name of dummy / temporary file
    dummy_file = original_file + '.bak'
    # Open original file in read only mode and dummy file in write mode
    with open(original_file, 'r') as read_obj, open(dummy_file, 'w') as write_obj:
        # Line by line copy data from original file to dummy file
        for line in read_obj:
            # If current line number exist in list then skip copying that line
            if counter not in line_numbers:
                write_obj.write(line)
            else:
                is_skipped = True
            counter += 1

    # If any line is skipped then rename dummy file as original file
    if is_skipped:
        os.remove(original_file)
        os.rename(dummy_file, original_file)
    else:
        os.remove(dummy_file)


Тогда ...

delete_multiple_lines('sample.txt', [0,1,2])


Проблема с этим методом может заключаться в том, что, если ваш файл имеет 1-100 строк для удаления, у вас будет указать [0,1,2 ... 100]. Правильно?


Ответ
Предоставлено @ sandes

Следующий код будет:

  • удалить первые 63
  • получить следующие 95
  • игнорировать остальные
  • создать новый файл


with open("sample.txt", "r") as f:
    lines = f.readlines()
    new_lines = []
    idx_lines_wanted = [x for x in range(63,((63*2)+95))]
    # delete first 63, then get the next 95
    for i, line in enumerate(lines):
        if i > len(idx_lines_wanted) -1:
            break
        if i in idx_lines_wanted:
             new_lines.append(line)

with open("sample2.txt", "w") as f:
    for line in new_lines:
        f.write(line)

Ответы [ 2 ]

2 голосов
/ 17 марта 2020

РЕДАКТИРОВАТЬ: итерации непосредственно по f

на основе комментариев @ Кенни и предложения @ chepner

with open("your_file.txt", "r") as f:
    new_lines = []
    for idx, line in enumerate(f):
        if idx in [x for x in range(2,5)]: #[2,3,4]
            new_lines.append(line)

with open("your_new_file.txt", "w") as f:
    for line in new_lines:
        f.write(line)
1 голос
/ 17 марта 2020

Это действительно то, что лучше всего обрабатывается настоящим текстовым редактором.

import subprocess

subprocess.run(['ed', original_file], input=b'1,2d\n+3,$d\nwq\n')

курс sh в ed, стандартный текстовый редактор POSIX.

ed открывает файл, названный его аргументом. Затем он продолжает чтение команд со своего стандартного ввода. Каждая команда представляет собой один символ, причем некоторые команды принимают один или два «адреса», чтобы указать, с какими строками работать.

После каждой команды «текущий» номер строки устанавливается на строку, на которую последний раз воздействовал команда. Это используется с относительными адресами, как мы увидим ниже.

  • 1,2d означает удаление строк с 1 по 2; текущая строка установлена ​​в 2
  • +3,$d удаляет все строки из строки 5 (текущая строка 2, поэтому 2 + 3 == 5) до конца файла ($ является специальным адрес, указывающий последнюю строку файла)
  • wq записывает все изменения на диск и закрывает редактор.
...