Заменить определенную строку в файле в Python

Для начала, поскольку меня уже обжигал кто-то с энергетическим трипом, этот вопрос не для домашнего задания.

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

####
# File section 1
####

1.0   abc   Description1
6.5   def   Description2
1.0 2.0 3.0   ghi   Description3
11    jkl   Description

####
# File section 2
####

1.0   abc   Description1
12.5   def   Description2
1.0 2.0 3.0   ghi   Description3
11    jkl   Description

#### End file

Я хотел бы заменить строку «1.0» в двух строках:

1.0   abc   Description1

Однако НЕ строка «1.0» в строках:

1.0 2.0 3.0   ghi   Description3

Текущий код, который я использую:

with open('sample_file.txt','r') as file:
    filedata = file.read()
    filedata = filedata.replace('1.0','2.0')
with open('sample_file.txt','w') as file:
    file.write(filedata)

Однако в результате все вхождения «1.0» заменяются. Затем я должен вернуться в файл и исправить ошибку. Результирующий файл, который я хотел бы получить:

####
# File section 1
####

2.0   abc   Description1
6.5   def   Description2
1.0 2.0 3.0   ghi   Description3
11    jkl   Description

####
# File section 2
####

2.0   abc   Description1
12.5   def   Description2
1.0 2.0 3.0   ghi   Description3
11    jkl   Description

#### End file

Как я могу это получить? Я не смог найти пример решения проблемы такого типа. Спасибо за вашу помощь.

Обновлено: Моя вина в том, что я не уточняю, но строка, которую я хочу заменить, не всегда имеет «1.0» и не всегда имеет длину 3 символа. Например, это может быть «-12,3». Я хотел бы сделать код как можно более универсальным.

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

========================

РЕДАКТИРОВАТЬ2: я нашел способ сделать это, хотя это кажется довольно обходным методом:

with open('sample_file.txt','r') as file:
    filedata = file.readlines()
        for line in filedata:
            if 'abc' in line:
                oriline = line
                newline = line.replace(str(spk),str(newspk))
with open('sample_file.txt','r') as file:
    filedata = file.read()
    filedata = filedata.replace(str(oriline),str(newline))
with open('sample_file.txt','w') as file:
    file.write(filedata)

По сути, он открывает файл, считывает строку за строкой всю строку, содержащую конкретную строку, которую я хочу, а затем просто сохраняет ее в памяти. Затем снова откройте файл, прочитайте все и просто замените всю эту строку. Затем откройте файл и запишите файл.

Он делает то, что я хочу, но есть ли способ упростить код?

Используйте регулярные выражения, чтобы найти нужный шаблон строки и выполнить замену части этого шаблона. Нам трудно дать вам более конкретный ответ, не зная точно, каковы критерии того, что вы хотите заменить (т. е. хотите ли вы заменить «1.0» только для записей с пометкой «abc»? хотите ли вы заменить «1.0 " только если в той же строке нет других чисел?)

jamesdlin 02.03.2019 18:24

Я хотел бы только заменить строку «1.0» для строк только на «abc» в них, поскольку «abc» — это переменная в коде, который я использую.

user3654549 02.03.2019 19:34

Что касается EDIT2: нет причин читать файл дважды. Вы можете изменить элементы filedata на месте, а затем использовать file.writelines на filedata. Кроме того, есть только один oriline, поэтому, если «abc» встречается дважды в одном и том же файле (как в вашем примере), это не сработает. Кроме того, вы выполните замену, если «abc» встречается в строке в любом месте (включая описание), и замените все вхождения spk на newspk (какими бы они ни были), а не только в первом токене. Вы также заявляете, что заменяемая строка не является фиксированной строкой, которую ваш подход не обрабатывает.

jamesdlin 03.03.2019 19:14

Что не так с любым из двух предложенных мной подходов? Они должны соответствовать требованиям, которые вы указали. Если они не подходят, объясните, почему.

jamesdlin 03.03.2019 19:16
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
4
10 533
2

Ответы 2

Просто используйте

with open('sample_file.txt','r') as file:
    filedata = file.read()
    filedata = filedata.replace('1.0   abc','2.0   abc')
with open('sample_file.txt','w') as file:
    file.write(filedata)

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

li = []

а затем используйте приведенный ниже код (учитывая, что строка abc фиксирована, как в приведенном выше случае):

with open('sample_file.txt','r') as file:
for line in file:
        i = line.find('abc',1)
        if i >= 0:
              lineval = line.replace('1.0','2.0')
              li.append(lineval)
        else:
              lineval = line
              li.append(lineval)
j = 0                 
with open('sample_file.txt','w') as file:
    while j < len(li):
        file.write(li[j])           
        j += 1

Моя вина в том, что я не уточнил, но строка, которую я хочу заменить, не всегда имеет «1.0» и не всегда имеет длину 3 символа. Например, это может быть «-12,3». Я хотел бы сделать код как можно более универсальным.

user3654549 02.03.2019 19:31

Этого может быть достаточно для случая OP, но имейте в виду, что второй пример кода заменит все вхождения «1.0», если в строке появится «abc» в любом месте.

jamesdlin 03.03.2019 02:31

@jamesdlin, конечно, я сделал это намеренно в зависимости от ключевого слова в его образце. Спасибо, в любом случае.

Barbaros Özhan 03.03.2019 05:16

Я попробовал свой собственный метод (EDIT 2), вдохновленный вами, ребята, и, похоже, он работает. Можете ли вы, ребята, предложить некоторую критику того, как я могу улучшить код?

user3654549 03.03.2019 15:25

Как я упоминал в комментарии, вы можете использовать регулярные выражения для соответствия шаблону, который вы ищете. Вы можете указать группы в шаблоне (используя (...) или (?P<имя...)), чтобы идентифицировать части шаблона и специально заменить или повторно использовать эти части.

Что-то вроде этого должно работать:

import re

pattern = (r'^' # The beginning of a line.
           # Match something that looks like a number:
           r'-?'        # 1. Optional: a negative sign.
           r'\d+'       # 2. One or more digits.
           r'([.]\d+)?' # 3. Optional: a decimal point followed by one
                        #    or more digits.
           # The rest of the line:
           r'(?P<rest>'
             r'\s+' # 1. One or more spaces.
             r'abc' # 2. "abc"
             r'\s+' # 3. One or more spaces.
             r'.*'  # 4. Everything remaining.
           r')' 
           r'$') # The end of a line.

# Replace the above pattern with "2.0" followed by whatever we identified
# as "the rest of the line".
replacement = '2.0\g<rest>'

with open('sample_file.txt','r') as file:
    filedata = file.read()

    # re.MULTILINE is needed to treat lines separately.
    filedata = re.sub(pattern, replacement, filedata, flags=re.MULTILINE)
with open('sample_file.txt','w') as file:
    file.write(filedata)

Другой (непроверенный) подход, который не использует регулярные выражения:

with open('sample_file.txt','r') as file:
    lines = file.readlines()

with open('sample_file.txt','w') as file:
    for line in lines:
        tokens = line.split(maxsplit=2)
        try:
            if float(tokens[0]) and tokens[1] == 'abc':
                tokens[0] = '2.0'
        except (IndexError, ValueError):
            pass
        else:
            line = ' '.join(tokens)
        file.write(line)

Обратите внимание, что это не совсем то же самое, что подход регулярных выражений (RE) (заметные отличия заключаются в том, что он будет принимать любое число с плавающей запятой в качестве первого токена (например, 1e-10) и что он не будет сохранять пробелы после выполнения замены ), но может быть немного проще понять, если вы не знакомы с RE.

Другие вопросы по теме