如果您已经能够解析这种格式(我已经用 pyParsing 尝试过,但如果您已经有一个有效的 flexx/bison 解决方案,那会很好),并且解析的数据很适合内存,那么您'基本上在那里。您可以将从每个文件中读取的内容表示为一个简单的对象,其中包含一个用于“一般输入”的字典和一个字典列表,每个实例一个(或者可能更好的是实例字典,键是实例编号,这可能给你更多的灵活性)。然后,正如您所提到的,您只需选择性地“更新”(添加或覆盖)一些从 master 复制到场景中的实例,写入新的场景文件,用它替换旧的。
要将 flexx/bison 代码与 Python 一起使用,您有多种选择——将其转换为 DLL/so 并使用 ctypes 访问它,或者从 cython 编码的扩展、SWIG 包装器、Python C-API 扩展中调用它,或者SIP、Boost等
假设,无论哪种方式,您有一个解析器原语(例如)接受输入文件名,读取并解析该文件,并返回一个 2 字符串元组列表,每个元组是以下之一:
- (参数名,参数值)
- ('$$$$', '一般输入')
- ('$$$$', '新实例')
只是使用 '$$$$' 作为一种任意标记。然后对于代表您从文件中读取的所有内容的对象,您可能拥有:
import re
instidre = re.compile(r'NEW\((\d+)\)')
class Afile(object):
  def __init__(self, filename):
    self.filename = filename
    self.geninput = dict()
    self.instances = dict()
  def feed_data(self, listoftuples):
    it = iter(listoftuples)
    assert next(it) == ('$$$$', 'General Inputs')
    for name, value in it:
      if name == '$$$$': break
      self.geninput[name] = value
    else:  # no instances at all!
      return
    currinst = dict()
    for name, value in it:
      if name == '$$$$':
        self.finish_inst(currinst)
        currinst = dict()
        continue
      mo = instidre.match(name)
      if mo:
        assert value == '.TRUE.'
        name = '$$$INSTID$$$'
        value = mo.group(1)
      currinst[name] = value
    self.finish_inst(currinst)
  def finish_inst(self, adict):
    instid = dict.pop('$$$INSTID$$$')
    assert instid not in self.instances
    self.instances[instid] = adict
健全性检查可能会有所改进,可以更准确地诊断异常,但我认为这大致是您想要的。
合并只需要foo.instances[instid] = bar.instances[instid]对所需的值进行操作instid,其中foo是Afile场景文件的实例,bar是主文件的实例——它将根据需要覆盖或添加。
我假设要写出新更改的场景文件,您不需要重复特定输入可能具有的所有格式怪癖(如果这样做,那么在解析过程中需要记录这些怪癖以及名称和值) ,所以简单地循环sorted(foo.instances)并按排序顺序写出每个内容(在编写一般内容后也按排序顺序,并使用适当的$ this and that标记行,并正确翻译'$$$INSTID$$$'条目等)就足够了。