简体   繁体   中英

String Replacement Not Being Written to File

I need to edit a certain file for a DoE study. The file is in the format:

1 Wall1
roughness 0.0
velocity 0.0
temperature "temperature.file"
########
2 Wall2
roughness 0.0
velocity 0.0
temperature "temperature.file"
########
3 Wall3
roughness 0.0
velocity 0.0
temperature "temperature.file"
########
4 Wall4
roughness 0.0
velocity 0.0
temperature 34.1
########
5 Roof
roughness 0.0
velocity 0.0
temperature "temperature.file"
########

For the DoE, I would like to change one or more "temperature.file" entries (which is a spatially varying temperature field of a region) for each case. So for example, case 2 would have Wall2's temperature file changed to "temperature2.file". The program will then know to find the new file instead of the original.

I have established the nested for loop, but struggling with the file I/O. The code that I have now is:

if m == 2:
    with open(newfolder2+'/walls.in','r') as file:
        filedata = file.readlines()
        for line in filedata:
            if 'Wall2' in line:
                for line in filedata:
                    if 'temperature' in line:
                        print line
                        line = line.replace('temperature.file','temperature2.file')
                        print line
                        break
#       file.seek(0)

    with open(newfolder2+'/walls.in','w') as file:
        file.writelines(filedata)

So essentially I want to to find the line where "Wall2" occurs, then look for the line with temperature after Wall2, then change that, and only that line's "temperature.file" string to "temperature2.file". Then exit the file, and then write to the file, thus creating the new input file for that particular case.

The first print line I have does print out the original line, and the second print line code also correctly prints out the altered line. However, it just seems that the file data isn't being written successfully back to the file.

What seems to be going wrong?

An alternative method, instead of all the nested loops to find a particular line, I thought, was to just use the file.seek() option. The lines and total length of the walls.in file will stay the same, so I can just go straight to that particular line to change the "temperature.in" string. Is this a better approach? I've never tried this, so some sample code would be greatly appreciated.

Thank you all very much!

When you iterate over the lines what you get in line is a copy of the original line.

What you could do is something like this where you split up the content of you file in chunks. As each section in your file end with ######## we can use that to split the file into chunks. You can then change the chunk you find and write it back to filedata before saving it.

with open(newfolder2+'/walls.in', 'r') as file:
filedata = file.read().split("########")
for i, chunk in enumerate(filedata):
    if "Wall2" in chunk:
        chunk = chunk.replace('temperature.file', 'temperature2.file')
        filedata[i] = chunk

with open(newfolder2+'/walls.in', 'w') as file:
    file.writelines("########".join(filedata))

you never assign anything new to your filedata .

you could write something like a parser that is aware of the context (here: the wall number you are in). this might look something like this:

from io import StringIO

# thie u is needed in python < 3
txt = u"""1 Wall1
roughness 0.0
velocity 0.0
temperature "temperature.file"
########
2 Wall2
roughness 0.0
velocity 0.0
temperature "temperature.file"
########
"""

wall = None
with StringIO(txt) as infile, StringIO() as outfile:
    for line in infile:
        if " Wall" in line:
            wall = int(line[:2])
        if wall == 2:
            if '"temperature.file"' in line:
                line = line.replace('"temperature.file"', '"temperature2.file"')
        outfile.write(line)

    print(outfile.getvalue())

to really read/write your files you would have to change the with line with

with open(newfolder2+'/walls.in','r') as infile, 
     open(newfolder2+'/walls.out','w') as outfile:

and remove the line that contains outfile.getvalue() . and then you would have to rename walls.out back to walls.in . that way your original file does not get lost if the program does something you did not want.

this might be easy to adapt if you wanted to change other lines for other Wall s.

There's two mistakes that are happening here.

  1. When you iterate in a for loop, the changing variable is initialized locally and changing that doesn't actually change the object being looped over.
>>> a = [5,4,3,7,1]
>>> for i in a:
...     i=2  # this won't change the elements of a!
... 
>>> a
[5, 4, 3, 7, 1]
  1. The way you have structured it, the second for loop will iterate over filedata from the very beginning again after finding Wall2 . This is because the for loop doesn't itself know that it is being run inside another for loop. You'll end up getting wrong results even if you fix 1. Either use an iterator to loop over filedata or use f.readline() which is a generator itself.
filedata=iter(filedata)

The following code should work:

filedata = []
with open('myfile') as f:
    line = ''
    while 'Wall2' not in line:
        line = f.readline()
        filedata.append(line)
    while 'temperature' not in line:
        line = f.readline()
        filedata.append(line)
    filedata.append(line.replace('temperature.file','temperature2.file'))

with open('myfile', 'w') as f:
    f.writelines(filedata)

I would however not do this. If you know that the file is always in the same format and the line number is always going to stay constant, use file.seek . It should be much faster. Also see Is it possible to modify lines in a file in-place? if you want to modify the file in place.

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