-1

Currently I have a program that accepts a text file as a setting parameter. The format of the text file is like so:

text file format

What I would like to do in Python is to be able to parse the file. I want to read each line and check if it contains a specific string and if the line contains it, be able to append/update in place a user input text right into the end of that line.

For example, the "PRIMER_PRODUCT_SIZE_RANGE=" (highlighted) is found in the text file and I want to update it from "PRIMER_PRODUCT_SIZE_RANGE=100-300" to read for example "PRIMER_PRODUCT_SIZE_RANGE=500-1000". I want to be able to do this for several of the parameters (that I have chosen for my needs).

A few tools I've looked into would include fileinput module, doing a regular file open/write (which I can't do in place editing apparently), and a module I found called the in_place module.

Some preliminary code I have using the in_place module:

def SettingFileParser(filepath):
    with in_place.InPlaceText(filepath) as text_file:
        for line in text_file:
            if 'PRIMER_PRODUCT_SIZE_RANGE=' in line:
                text_file.write("idk what to put here")

I'm a noob programmer to preface so any help or guidance in the right direction would be appreciated.

Thunderpurtz
  • 189
  • 2
  • 12
  • Do you need to be able to directly read the file, I was thinking of using pickle –  Aug 03 '18 at 02:26

3 Answers3

0

You need to open the file for reading (default) and then you need to open a file for writing:

def SettingFileParser(filepath):
    with open(filepath, 'r') as read_file:
        lines = read_file.readlines():
        with open(filepath, 'w') as write_file:
            for line in lines:
                if line.startswith('PRIMER_PRODUCT_SIZE_RANGE='):
                    # keep the line the same except the part needing replacement
                    write_file.write(line.replace('100-300','500-1000'))
                else:
                    # otherwise just write the line as is
                    write_file.write(line)
cosmic_inquiry
  • 2,557
  • 11
  • 23
  • this was sort of what I was thinking, but for the line where you put: write_file.write(line.replace('100-300','500-1000')) I would need the 100-300 part to be variable as it would depend on whats already there wouldn't it? – Thunderpurtz Aug 03 '18 at 17:06
  • Yeah I see what you're saying. Instead you can do: `write_file.write(line.replace(line.split('=')[1],'500-1000'))` – cosmic_inquiry Aug 03 '18 at 17:14
  • to my understanding, the line.split[1] part essentially finds the = sign then splits the string into two separate portions. is it stored in an array of some sort which allows for the [1] index to access and replace the portion after? – Thunderpurtz Aug 03 '18 at 17:22
  • yeah that's correct. So if we had 'foo=bar'.split('=')[1] it would first produce a list ['foo', 'bar'], and by using index 1 we access the second element in that list - 'bar' (python being zero indexed). – cosmic_inquiry Aug 03 '18 at 17:30
0

For this task, regular expressions are the way to go. I refer you to this post.

Concretely, something like this might do the trick:

import re
# read in file here...
re.sub(r"PRIMER_PRODUCT_SIZE_RANGE=[0-9,-]*", "PRIMER_PRODUCT_SIZE_RANGE=500-1000", s)

Here, s would be the entire string in the text file.

Lutz Büch
  • 343
  • 4
  • 12
  • 1
    I have thought about regex but I confess that I really have never done it before. But maybe this is an excuse to go and learn it now! – Thunderpurtz Aug 03 '18 at 17:07
0

You can use re for changing/manipulating strings (explanation of this regex on external site):

data = """
# PRIMER_PRODUCT_SIZE_RANGE=xxx-yyy
PRIMER_PRODUCT_SIZE_RANGE=100-300
PRIMER_NUM_RETURN=3
PRIMER_MAX_END_STABILITY=9.0

PRIMER_MAX_HAIRPIN_TH=24.0
"""

import re

def change_parameter(data, parameter, new_value):
    return re.sub(r'^(\s*(?<!#)\s*{}\s*)=.*$'.format(parameter), r'\1={}'.format(new_value), data, flags=re.M|re.I)

data = change_parameter(data, 'PRIMER_PRODUCT_SIZE_RANGE', '100-500')
data = change_parameter(data, 'PRIMER_MAX_HAIRPIN_TH', '99.9')
print(data)

This prints:

# PRIMER_PRODUCT_SIZE_RANGE=xxx-yyy
PRIMER_PRODUCT_SIZE_RANGE=100-500
PRIMER_NUM_RETURN=3
PRIMER_MAX_END_STABILITY=9.0

PRIMER_MAX_HAIRPIN_TH=99.9

For reading/writing to file you can use this snippet:

with open('parameters.txt', 'r', newline='') as f_in:
    data = f_in.read()

with open('parameters.txt', 'w', newline='') as f_out:
    data = change_parameter(data, 'PRIMER_PRODUCT_SIZE_RANGE', '100-500')
    data = change_parameter(data, 'PRIMER_MAX_HAIRPIN_TH', '99.9')
    f_out.write(data)

EDIT:

Extended version of change_parameter():

import re
data = """
PRIMER_PRODUCT_SIZE_RANGE=100-500 200-400
PRIMER_NUM_RETURN=3
PRIMER_MAX_END_STABILITY=9.0
"""

def change_parameter_ext(data, parameter, old_value, new_value):
    def _my_sub(g):
        return g[1] + '=' + re.sub(r'{}'.format(old_value), new_value, g[2], flags=re.I).strip()
    return re.sub(r'^(\s*(?<!#)\s*{}\s*)=(.*)$'.format(parameter), _my_sub, data, flags=re.M|re.I).strip()

data = change_parameter_ext(data, 'PRIMER_PRODUCT_SIZE_RANGE', '200-400', '500-600')
data = change_parameter_ext(data, 'PRIMER_NUM_RETURN', '3', '100-200 300-400')
print(data)

Prints:

PRIMER_PRODUCT_SIZE_RANGE=100-500 500-600
PRIMER_NUM_RETURN=100-200 300-400
PRIMER_MAX_END_STABILITY=9.0
Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • the actual example for product size can be more complicated than that too as multiple size ranges can be specified in the text file of this format (example): "100-300 400-1000 150-250" where the ranges are separated by a space and there can be any number of ranges. I would essentially want everything after the = sign to be overwritten by user input – Thunderpurtz Aug 03 '18 at 17:09
  • @Thunderpurtz see my edited answer. You can specify old parameter and to what parameter it shall change. – Andrej Kesely Aug 03 '18 at 17:27