0

入力が次の形式のASCIIファイルに含まれている実行可能ファイルがあります。

$ GENERAL INPUTS
$ PARAM1 = 123.456
PARAM2=456,789,101112
PARAM3(1)=123,456,789
PARAM4       =
1234,5678,91011E2
PARAM5(1,2)='STRING','STRING2'
$ NEW INSTANCE
NEW(1)=.TRUE.
PAR1=123
[More data here]
$ NEW INSTANCE
NEW(2)=.TRUE.
[etcetera]

言い換えると、いくつかの一般的な入力と、いくつかの新しいインスタンスのいくつかのパラメーター値です。パラメータの宣言は不規則です。一部の数値はコンマで区切られ、その他は科学的記数法で、その他は引用符で囲まれ、間隔は一定ではありません。

一部のシナリオの評価では、1つの「マスター」データファイルを入力し、たとえばインスタンス2〜6のパラメータデータを、そのインスタンスのデータがすでに含まれている可能性のある別のデータファイルにコピーする必要があります(この場合、データは上書きされる)および場合によっては他のデータ(変更されないままにする必要があるデータ)。

FlexレクサーとBisonパーサーを作成しました。一緒にデータファイルを食べて、パラメータをメモリに保存できます。それらを使用して両方のファイル(マスターと「シナリオ」)を開く場合、3番目の新しいファイルに(のように"general input from 'scenario'; instances 1 though 5 from 'master'; instances 6 through 9 from 'scenario'; ...")必要なパラメーターを選択的に書き込み、保存して、元のシナリオファイルを削除するのはそれほど難しくありません。

その他の情報:(1)ファイルは非常に機密性が高いため、ユーザーがマスターファイルを変更しないように完全に保護することが非常に重要です。(2)ファイルは管理可能なサイズ(500Kから10M)です。

私は10行のコードで何ができるかを学びました。ここにいる仲間の中には2行でできる人もいます。この問題にどのようにアプローチしますか?パイソンの答えは私を泣かせるでしょう。真剣に。

4

1 に答える 1

1

この形式をすでに解析でき(pyParsingで試しましたが、flexx / bisonソリューションがすでに機能している場合は、それで問題ありません)、解析されたデータがメモリにうまく収まる場合は、 '基本的にそこにあります。各ファイルから読み取ったものを、「一般的な入力」のdictと、インスタンスごとに1つのdictのリスト(または、インスタンスのdictで、キーがインスタンス番号である場合があります)を含む単純なオブジェクトとして表すことができます。もう少し柔軟性があります)。次に、前述のように、マスターからシナリオにコピーされたインスタンスの一部を選択的に「更新」(追加または上書き)し、新しいシナリオファイルを書き込み、古いシナリオファイルを置き換えます。

Pythonでflexx/bisonコードを使用するには、いくつかのオプションがあります。DLL/ soにして、ctypesでアクセスするか、cythonでコード化された拡張機能、SWIGラッパー、PythonC-API拡張機能から呼び出します。 SIP、Boostなど。

何らかの方法で、(たとえば)入力ファイル名を受け入れ、そのファイルを読み取って解析し、それぞれが次のいずれかである2文字列タプルのリストを返すパーサープリミティブがあるとします。

  • (paramname、paramvalue)
  • ('$$$$'、'一般的な入力')
  • ('$$$$'、'新しいインスタンス')

'$$$$'を一種の任意のマーカーとして使用するだけです。次に、ファイルから読み取ったすべてを表すオブジェクトの場合、次のようになります。

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のインスタンスであり、はマスターファイルのインスタンスです。これは必要に応じて上書きまたは追加されます。Afilebar

新しく変更されたシナリオファイルを書き出すために、特定の入力が持つ可能性のあるすべてのフォーマットの癖を繰り返す必要はないと思います(そうする場合、それらの癖は、名前と値と一緒に解析中に記録する必要があります) 、したがって、単純にループしてsorted(foo.instances)、それぞれをソートされた順序で書き出す(一般的なものもソートされた順序で、適切な$ this and thatマーカー行を使用し、'$$$INSTID$$$'エントリを適切に翻訳した後など)で十分です。

于 2009-11-08T23:21:08.227 に答える