0

I am running Python 3.5.1

I have a text file that I'm trying to search through and replace or overwrite text if it matches a predefined variable. Below is a simple example:

test2.txt

A Bunch of Nonsense Stuff
############################
# More Stuff Goes HERE     #
############################
More stuff here
Outdated line of information that has no comment above - message_label

The last line in this example needs to be overwritten so the new file looks like below:

test2.txt after script

A Bunch of Nonsense Stuff
############################
# More Stuff Goes HERE     #
############################
More stuff here

# This is an important line that needs to be copied
Very Important Line of information that the above line is a comment for - message_label

The function I have written idealAppend does not work as intended and subsequent executions create a bit of a mess. My workaround has been to separate the two lines into single line variables but this doesn't scale well. I want to use this function throughout my script with the ability to handle any number of lines. (if that makes sense)

Script

#!/usr/bin/env python3
import sys, fileinput, os
def main():

    file = 'test2.txt'
    fullData = r'''
# This is an important line that needs to be copied
Very Important Line of information that the above line is a comment for - message_label
'''
    idealAppend(file, fullData)


def idealAppend(filename, data):
    label = data.split()[-1]                                            # Grab last word of the Append String
    for line in fileinput.input(filename, inplace=1, backup='.bak'):
        if line.strip().endswith(label) and line != data:               # If a line 2 exists that matches the last word (label)
            line = data                                                 # Overwrite with new line, comment, new line, and append data.
        sys.stdout.write(line)                                          # Write changes to current line

    with open(filename, 'r+') as file:                                  # Open File with rw permissions
        line_found = any(data in line for line in file)                 # Search if Append exists in file

        if not line_found:                                              # If data does NOT exist
            file.seek(0, os.SEEK_END)                                   # Goes to last line of the file
            file.write(data)                                            # Write data to the end of the file


if __name__ == "__main__": main()

Workaround Script
This seems to work perfectly as long as I only need to write exactly two lines. I'd love this to be more dynamic when it comes to number of lines so I can reuse the function easily.

#!/usr/bin/env python3
import sys, fileinput, os
def main():

    file = 'test2.txt'
    comment = r'# This is an important line that needs to be copied'
    append = r'Very Important Line of information that the above line is a comment for - message_label'

    appendFile(file, comment, append)

def appendFile(filename, comment, append):

    label = append.split()[-1]                                          # Grab last word of the Append String
    for line in fileinput.input(filename, inplace=1, backup='.bak'):
        if line.strip().endswith(label) and line != append:             # If a line 2 exists that matches the last word (label)
            line = '\n' + comment + '\n' + append                       # Overwrite with new line, comment, new line, and append data.
        sys.stdout.write(line)                                          # Write changes to current line

    with open(filename, 'r+') as file:                                  # Open File with rw permissions
        line_found = any(append in line for line in file)               # Search if Append exists in file

        if not line_found:                                              # If data does NOT exist
            file.seek(0, os.SEEK_END)                                   # Goes to last line of the file
            file.write('\n' + comment + '\n' + append)                  # Write data to the end of the file

if __name__ == "__main__": main()

I am very new to Python so I'm hoping there is a simple solution that I overlooked. I thought it might make sense to try and split the fullData variable at the new line characters into a list or tuple, filter the label from the last item in the list, then output all entries but this is starting to move beyond what I've learned so far.

3 Answers 3

1

If I understand your issue correctly, you can just open the input and output files, then check whether the line contains old information and ends with the label and write the appropriate content accordingly.

with open('in.txt') as f, open('out.txt', 'r') as output:
    for line in f:
        if line.endswith(label) and not line.startswith(new_info):
            output.write(replacement_text)
        else:
            output.write(line)

If you want to update the original file instead of creating a second one, it's easiest to just delete the original and rename the new one instead of trying to modify it in place.

Sign up to request clarification or add additional context in comments.

Comments

0

Is this what you are looking for ? It's looking for a label and then replaces the whole line with whatever you want.

test2.txt

A Bunch of Nonsense Stuff
############################
# More Stuff Goes HERE     #
############################
More stuff here

Here is to be replaced - to_replace

script.py

#!/usr/bin/env python3

def main():
    file = 'test2.txt'
    label_to_modify = "to_replace"
    replace_with = "# Blabla\nMultiline\nHello"
    """
    # Raw string stored in a file
    file_replace_with = 'replace_with.txt'
    with open(file_replace_with, 'r') as f:
        replace_with = f.read()
    """
    appendFile(file, label_to_modify, replace_with)

def appendFile(filename, label_to_modify, replace_with):
    new_file = []
    with open(filename, 'r') as f:
        for line in f:
            if len(line.split()) > 0 and line.split()[-1] == label_to_modify:
                new_file.append(replace_with)
            else:
                new_file.append(line)

    with open(filename + ".bak", 'w') as f:
        f.write(''.join(new_file))

if __name__ == "__main__": main()

test2.txt.bak

A Bunch of Nonsense Stuff
############################
# More Stuff Goes HERE     #
############################
More stuff here

# Blabla
Multiline
Hello

3 Comments

This would work great except I need the "replace_with" string to be a raw string, which would disable the \n. There are a number of instances where it would contain backslashes, double quotes, etc and escaping each character that could cause a problem is something I wanted to avoid if possible.
Where is this "raw string" coming from ?
I edited my answer with another possibility. You could store this raw string in a file, and read from it.
0

Reading over both answers I've come up with the following as the best solution i can get to work. It seems to do everything I need. Thanks Everyone.

#!/usr/bin/env python3

def main():

    testConfFile = 'test2.txt' # /etc/apache2/apache2.conf
    testConfLabel = 'timed_combined'
    testConfData = r'''###This is an important line that needs to be copied - ##-#-####
Very Important Line of information that the above line is a \"r\" comment for - message_label'''

    testFormatAppend(testConfFile, testConfData, testConfLabel)     # Add new test format

def testFormatAppend(filename, data, label):
    dataSplit = data.splitlines()
    fileDataStr = ''

    with open(filename, 'r') as file:
        fileData = stringToDictByLine(file)

    for key, val in fileData.items():
        for row in dataSplit:
            if val.strip().endswith(row.strip().split()[-1]):
                fileData[key] = ''

    fileLen = len(fileData) 
    if fileData[fileLen] == '':
        fileLen += 1
        fileData[fileLen] = data
    else:
        fileLen += 1
        fileData[fileLen] = '\n' + data

    for key, val in fileData.items():
        fileDataStr += val

    with open(filename, 'w') as file:
        file.writelines(str(fileDataStr))


def stringToDictByLine(data):
    fileData = {}
    i = 1
    for line in data:
        fileData[i] = line
        i += 1
    return fileData

if __name__ == "__main__": main()

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.