Jian Xu
Jian Xu

Reputation: 15

Replace the data/string inside a text-like file

I am trying to automate some parts of my work. I have a INP file which is text-like (but not .txt file) and contains both strings and ints/floats. I'd like to replace certain columns from the 6 to the end rows with the values in the output(result) of a loop.

Here's what I want to accomplish for the test.INP:

  1. Keep the first 5 lines, replace the data from columns 3-5 with those data in result. Hopefully, the final test.INP file is not newly created but the data has been replaced.

  2. Because the dimension of the data to be replaced with and the target data in result is the same, to avoid the first 5 lines, I am trying to define a function to reversely read line by line and replace test.INP file.

Python script:

...
with open('test.INP') as j:
    raw = j.readlines()

    def replace(raw_line, sep='\t', idx=[2, 3, 4], values=result[-1:]):
        temp = raw[-1].split('\t')
        for i, v in zip(idx, values):
            temp[i] = str(v)
        return sep.join(temp)

    raw[::-1] = replace(raw[::-1])

print('\n'.join(raw))
...

test.INP contents (before):

aa bb cc dd
abcd
e
fg
cols1   cols2   cols3   cols4   cols5   cols6
65  69  433 66  72  70b
65  75  323 61  71  68g
61  72  12  57  73  26c

Result contents:

[[329   50  58]
 [258   47  66]
[451    38  73]]

My final goal is to get the test.INP below:

test.INP contents(after):

aa bb cc dd
abcd
e
fg
cols1   cols2   cols3   cols4   cols5   cols6
65  69  329 50  58  70b
65  75  258 47  66  68g
61  72  451 38  73  26c

But the code doesn't work as expected, seems nothing changed in the test.INP file. Any suggestions?

Getting error message at the bottom it says:

ValueError                                Traceback (most recent call last)
<ipython-input-1-92f8c1020af3> in <module>
     36                 temp[i] = str(v)
     37             return sep.join(temp)
---> 38         raw[::-1] = replace(raw[::-1])
     39 print('\n'.join(raw))

ValueError: attempt to assign sequence of size 100 to extended slice of size 8

Upvotes: 1

Views: 189

Answers (1)

furas
furas

Reputation: 142651

I coudn't understand your code so I build own version.

Later you understand what you try to do - you reverse lines to works from last until you use all results. Problem is that you forgot loop which will do it. You run replace only once and send all rows at once but replace works only with one row and it returns only one row - so finally you get one row (with 8 columns) and you want to assign in places of all rows (probably 100 rows)


Here version which works for me. I put text directly in code but I expect it will works also with text from file

text = '''aa bb cc dd
abcd
e
fg
cols1\tcols2\tcols3\tcols4\tcols5\tcols6
65\t69\t433\t66\t72\t70b
65\t75\t323\t61\t71\t68g
61\t72\t12\t57\t73\t26c'''

results = [[329, 50, 58], [258, 47, 66], [451, 38, 73]]
idx = [2,3,4]
sep = '\t'    

print(text)

#with open('test.INP') as j:
#    lines = j.readlines()
    
# split text to lines    
lines = text.splitlines()

def replace(line_list, result_list, idx):
    for i, v in zip(idx, result_list):
        line_list[i] = str(v)
    return line_list

# start at 5 line and group line (text) with values to replace    
for line_number, result_as_list in zip(range(5, len(lines)), results):
    # convert line from string to list
    line_list = lines[line_number].split(sep)
    
    # replace values
    line_list = replace(line_list, result_as_list, idx)
    
    # convert line from list to string
    lines[line_number] = sep.join(line_list)

# join lines to text
text = '\n'.join(lines)

print(text)

with open('test.INP', 'w') as j:
    j.write(text)

Upvotes: 1

Related Questions