1. Кратко
Имеется файл. В нём нужно произвести замены только на определённых линиях. Некоторые линии необходимо игнорировать.
Желательно сделать это без дублирующегося кода (для кода вроде п. 3.1 данного вопроса).
2. Минимальный пример
Kira.txt:
Sasha
Sasha*-U Can't Touch This
Sasha Goddess!
main.py
import re
with open("Kira.txt", "r+") as kira_file:
file_as_string = kira_file.read()
kira_file.seek(0)
kira_file.write(re.sub(r'Sasha', r'Kira', file_as_string, flags=re.M))
kira_file.truncate()
- Вывод (перезаписанный
main.py):
Kira
Kira*-U Can't Touch This
Kira Goddess!
А нужно, чтобы любая строка, содержащая Touch (в примере — вторая), не была затронута заменами. Touch — условная метка, показывающая, что модулю ничего не следует делать с данной линией. То есть, чтобы файл перезаписался так:
Kira
Sasha*-U Can't Touch This
Kira Goddess!
3. Попытки самостоятельно справиться с заданием
Пробовал также использовать метод writelines вместо write или модуль itertools — безуспешно.
3.1. Поиск и замена на линии
Попробую выполнить то же самое, что и в п.2, но чтобы поиск/замена велась для определённой линии.
"""Минимальный пример."""
import re
def initial_function():
"""Получаю список строк, в которых будет вестись поиск или замена.
В реальном модуле, чтобы получить список, выполняю много действий:
(https://www.pastery.net/npjxzx/).
В минимальном же примере в списке убираются строки, содержащие «Touch».
Строки, не вошедшие в список, это строки-исключения, в них поиск и замена
вестись не должны.
"""
with open("Kira.txt", "r+") as kira_file:
file_as_list = kira_file.readlines()
final_list = [_ for _ in file_as_list if 'Touch' not in _]
yield kira_file, final_list
def find_function():
"""Функция-пример.
Список, полученный в прошлой функции,
нужен, чтобы по его пунктам выполнить поиск на определённое вхождение.
Вставил эту функцию в пример, потому что хотелось бы рабочий код, где не пришлось бы
дублировать действия для получения списка неисключённых строк
для этой функции и в replace_function().
"""
for kira_file, final_list in initial_function():
for line in final_list:
if "Goddess" in line:
print(f"{line} contain Goddess")
else:
print(f"{line} not contain Goddess")
def replace_function():
"""В этой функции пытаюсь выполнить замену."""
for kira_file, final_list in initial_function():
for line in final_list:
kira_file.seek(0)
kira_file.write(re.sub(r'Sasha', r'Kira', line, flags=re.M))
kira_file.truncate()
# find_function()
replace_function()
- Вывод (перезаписанный
main.py):
Kira Goddess!
Всё удалилось кроме последней заменённой строки.
3.2. tell()
Пробовал не использовать seek(0) или использовать tell()
def replace_function():
"""В этой функции пытаюсь выполнить замену."""
for kira_file, final_list in initial_function():
for line in final_list:
# kira_file.seek(0)
kira_file.write(re.sub(r'Sasha', r'Kira', line, flags=re.M))
kira_file.truncate()
- или:
def replace_function():
"""В этой функции пытаюсь выполнить замену."""
for kira_file, final_list in initial_function():
for line in final_list:
last_pos = kira_file.tell()
kira_file.seek(last_pos)
kira_file.write(re.sub(r'Sasha', r'Kira', line, flags=re.M))
kira_file.truncate()
- Вывод (перезаписанный
main.py):
Sasha
Sasha*-U Can't Touch This
Sasha Goddess!Kira
Kira Goddess!
4. Пояснения
- Линии, где требуется и нет проводить замены, могут быть расположены в любом месте файла. Код, подобный этому, приспособить к решению данной задачи, у меня не вышло.
- Нужно перезаписать исходный файл, а не вывести конечный результат в новый файл. Использование временных файлов, если это необходимо, конечно, не возбраняется.
- Линии-исключения после проведения операции замены должны оставаться в файле. В них не требуется ничего изменять, но удалять нельзя. Вариант: записать заменённые линии в другой файл → перезаписать исходный файл, у меня не проходил.
find_function()нужно будет передать одну переменную, вreplace_function()— линтеры будут репортировать об unused variablefile_as_listна 29 строке кода. – Саша Черных Sep 04 '18 at 15:37r+, в итоге новое содержимое добавится в конец файла, а не перезапишет его, пример. Плюс те же unused variables. // Спасибо. – Саша Черных Sep 04 '18 at 15:37В вашем коде ничего не понял.— что именно, могли бы пояснить, чтобы я, в свою очередь, мог объяснить? Спасибо. – Саша Черных Sep 04 '18 at 15:55if 'Touch' not in lineвместе сelseне стоит использовать – vadim vaduxa Sep 04 '18 at 15:56find_function()нужна только переменнаяfinal_list, дляreplace_function— ещё и переменнаяkira_file. Вопрос в том, как передать переменные. Вижу 3 варианта: 1. Написать, как здесь, но тогда получится неиспользованная переменная (см. прошлые комментарии), 2. Использоватьglobal, что никогда не рекомендуется. 3. Писать дублирующийся код. Т. е. вreplace_functionполучать переменные так же, как и вinitial_function(). // Но, видимо, есть какой-то другой, правильный вариант. – Саша Черных Sep 05 '18 at 05:58оформляйте их в чистые функции, не тянущие за собой кучу контекста.— могли бы на примере показать? Что-то вроде этого не работает. Спасибо. – Саша Черных Sep 05 '18 at 05:59