简体   繁体   中英

Python modify text file by the name of arguments

I have a text file ( "input.param" ), which serves as an input file for a package. I need to modify the value of one argument. The lines need to be changed are the following:

param1        0.01
model_name    run_param1

I need to search the argument param1 and modify the value of 0.01 for a range of different values, meanwhile the model_name will also be changed accordingly for different value of param1 . For example, if the para1 is changed to be 0.03, then the model_name is changed to be 'run_param1_p03'. Below is some of my attempting code:

import numpy as np
import os


param1_range = np.arange(0.01,0.5,0.01)
with open('input.param', 'r') as file :
   filedata = file.read()

for p_value in param1_range:
    filedata.replace('param1        0.01', 'param1        ' + str(p_value))
    filedata.replace('model_name    run_param1', 'model_name    run_param1' + '_p0' + str(int(round(p_value*100))))

   with open('input.param', 'w') as file:
       file.write(filedata)

   os.system('./bin/run_app param/input.param')

However, this is not working. I guess the main problem is that the replace command can not recognize the space . But I do not know how to search the argument param1 or model_name and change their values.

I'm editing this answer to more accurately answer the original question, which it did not adequately do.

The problem is "The replace command can not recognize the space" . In order to do this, the re , or regex module, can be of great help. Your document is composed of an entry and its value, separated by spaces:

param1        0.01
model_name    run_param1

In regex, a general capture would look like so:

import re

someline = 'param1        0.01'
pattern = re.match(r'^(\S+)\s+(\S+)$', someline)

pattern.groups()
# ('param1', '0.01')

The regex functions as follows:

^ captures a start-of-line \\S is any non-space char, or, anything not in ('\\t', ' ', '\\r', '\\n') + indicates one or more as a greedy search (will go forward until the pattern stops matching) \\s+ is any whitespace char (opposite of \\S , note the case here) () indicate groups, or how you want to group your search

The groups make it fairly easy for you to unpack your arguments into variables if you so choose. To apply this to the code you have already:

import numpy as np 
import re

param1_range = np.arange(0.01,0.5,0.01)
filedata = []

with open('input.param', 'r') as file:
    # This will put the lines in a list
    # so you can use ^ and $ in the regex
    for line in file:
        filedata.append(line.strip()) # get rid of trailing newlines

# filedata now looks like:
# ['param1        0.01', 'model_name    run_param1']

# It might be easier to use a dictionary to keep all of your param vals
# since you aren't changing the names, just the values
groups = [re.match('^(\S+)\s+(\S+)$', x).groups() for x in filedata]

# Now you have a list of tuples which can be fed to dict()
my_params = dict(groups)
# {'param1': '0.01', 'model_name': 'run_param1'}

# Now just use that dict for setting your params
for p_value in param1_range:
    my_params['param1'] = str(p_value)
    my_params['model_name'] = 'run_param1_p0' + str(int(round(p_value*100)))

    # And for the formatting back into the file, you can do some quick padding to get the format you want
    with open('somefile.param', 'w') as fh:
        content = '\n'.join([k.ljust(20) + v.rjust(20) for k,v in my_params.items()])
        fh.write(content)

The padding is done using str.ljust and str.rjust methods so you get a format that looks like so:

for k, v in dict(groups).items():
    intstr = k.ljust(20) + v.rjust(20)
    print(intstr)

param1                              0.01
model_name                    run_param1

Though you could arguably leave out the rjust if you felt so inclined.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM