【问题标题】:String Replacement Not Being Written to File字符串替换未写入文件
【发布时间】:2019-10-09 14:12:11
【问题描述】:

我需要为 DoE 研究编辑某个文件。文件格式为:

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"
########

对于美国能源部,我想为每种情况更改一个或多个“temperature.file”条目(这是一个区域的空间变化温度场)。例如,案例 2 会将 Wall2 的温度文件更改为“temperature2.file”。然后程序将知道找到新文件而不是原始文件。

我已经建立了嵌套的 for 循环,但在文件 I/O 方面遇到了困难。我现在的代码是:

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)

所以本质上我想找到“Wall2”出现的行,然后在 Wall2 之后查找带有温度的行,然后将其更改,并且只有该行的“temperature.file”字符串为“temperature2.file”。然后退出文件,然后写入文件,从而为特定情况创建新的输入文件。

我的第一行打印出原始行,第二个打印行代码也正确打印出更改后的行。但是,文件数据似乎没有成功写回文件。

似乎出了什么问题?

我认为另一种方法是使用 file.seek() 选项,而不是使用所有嵌套循环来查找特定行。 wall.in 文件的行和总长度将保持不变,因此我可以直接转到该特定行来更改“temperature.in”字符串。这是更好的方法吗?我从来没有试过这个,所以一些示例代码将不胜感激。

非常感谢大家!

【问题讨论】:

  • 你永远不会改变filedata...

标签: python string python-2.7 replace io


【解决方案1】:

当你遍历这些行时,你得到的是原始行的副本。

你可以做的是这样的事情,你将文件的内容分成几块。由于文件中的每个部分都以######## 结尾,因此我们可以使用它将文件拆分为块。然后,您可以更改找到的块并将其写回 filedata,然后再保存。

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))

【讨论】:

    【解决方案2】:

    这里发生了两个错误。

    1. 当您在 for 循环中进行迭代时,更改的变量会在本地初始化,并且更改实际上不会更改被循环的对象。
    >>> 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. 按照您的结构方式,第二个 for 循环将在找到 Wall2 后再次从头开始迭代 filedata。这是因为 for 循环本身并不知道它正在另一个 for 循环中运行。即使您修复了 1,您最终也会得到错误的结果。要么使用迭代器循环 filedata,要么使用 f.readline(),它本身就是一个生成器。
    filedata=iter(filedata)
    

    以下代码应该工作:

    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)
    

    但我不会这样做。如果您知道文件始终采用相同的格式并且行号始终保持不变,请使用file.seek。它应该快得多。如果您想就地修改文件,另请参阅Is it possible to modify lines in a file in-place?

    【讨论】:

    • 非常感谢您的解释。虽然我没有机会尝试代码,但希望它可以帮助其他人。
    【解决方案3】:

    您永远不会为您的 filedata 分配任何新内容。

    您可以编写诸如解析器之类的东西,它知道上下文(这里:您所在的墙号)。这可能看起来像这样:

    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())
    

    要真正读/写您的文件,您必须更改 with

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

    并删除包含outfile.getvalue() 的行。然后您必须将walls.out 重命名为walls.in。这样,如果程序执行您不想要的操作,您的原始文件就不会丢失。

    如果您想为其他 Walls 更改其他行,这可能很容易适应。

    【讨论】:

    • 非常感谢您的解释。虽然我没有机会尝试代码,但希望它可以帮助其他人。
    猜你喜欢
    • 2018-04-27
    • 2010-11-11
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    相关资源
    最近更新 更多