0

foo.logツールによって生成された2つのログファイル(namedと)を比較するPythonスクリプトを作成したかっbar.logたのです。ログファイルには、無視できる行と無視できない行があります(比較のため)。

無視できる行を識別する正規表現を作成しました。コードを実装した方法は次のとおりです。

import re

p_1 = re.compile(...) # Pattern 1 to be ignored
p_2 = re.compile(...) # Pattern 2 to be ignored
p_3 = re.compile(...) # Pattern 3 to be ignored
...
p_n = re.compile(...) # Pattern n to be ignored

with open("foo.log", mode = 'r') as foo:
    with open("foo_temp.log", mode = 'w') as foo_temp:
        for foo_lines in foo:
            if p_1.match(foo_lines):
                continue
            elif p_2.match(foo_lines):
                continue
            elif p_3.match(foo_lines):
                continue
            ...
            ...
            ...
            elif p_n.match(foo_lines):
                continue
            else:
                foo_temp.write(foo_lines)

with open("bar.log", mode = 'r') as bar:
    with open("bar_temp.log", mode = 'w') as bar_temp:
        for bar_lines in bar:
            if p_1.match(bar_lines):
                continue
            elif p_2.match(bar_lines):
                continue
            elif p_3.match(bar_lines):
                continue
            ...
            ...
            ...
            elif p_n.match(bar_lines):
                continue
            else:
                bar_temp.write(bar_lines)

スクリプトを実行すると、2つのファイルが取得され、foo_temp.log後でbar_temp.logWinMergeを使用して手動で比較します。以下は私の質問です:

1)正規表現の使い方を最適化できる方法はありますか(実際、正規表現は初めてで、その点で最適化できるものがたくさんあると感じています)

2)後で無視する新しいパターンを追加する必要がある場合、ユーザーの観点から新しいパターンを簡単に追加できるようにすることはできますか。(現在、新しいパターンを追加する必要があります。その後、2つの場所でチェックを行います。1つは用foo.log、もう1つは用ですbar.log

3)巨大なファイルを扱うときにジェネレーターが使われていると聞いたことがあります。私が比較するログは比較的小さいですが(最大50MB)、ジェネレーターがどのように使用されているかを調べて、スクリプトに組み込む必要がありますか?

4)WinMergeを使用して手動チェックを作成foo_temp.logbar_temp.logて実行するのではなく、Python自体で(縮小されたファイルの)比較を実行できる方法はありますか?filecmpおそらくモジュールから何か?

注:無視できる行の中には、両方のログで(順序が狂って)ごちゃ混ぜになっているものがあります。たとえば、foo.log次のようなパターンが考えられます。

Line 1: <<Pattern_1: Ignore>>
Line 2: <<Pattern_2: Do not Ignore>>
Line 3: <<Pattern_3: Do not Ignore>>
Line 4: <<Pattern_4: Do not Ignore>>
Line 5: <<Pattern_5: Ignore>>

一方bar.log、次のパターンがあります。

Line 1: <<Pattern_1: Ignore>>
Line 2: <<Pattern_5: Ignore>>
Line 3: <<Pattern_2: Do not Ignore>>
Line 4: <<Pattern_3: Do not Ignore>>
Line 5: <<Pattern_4: Do not Ignore>>

無視できる行を削除すると、両方のファイルのパターンが同じになることに注意してください。そのため、一度に無視できる行をすべて削除してから、縮小したファイルを比較することにしました。

4

1 に答える 1

1

あなたがどのような比較を考えていたのかはわかりませんdifflibが、便利かもしれませんが、私が知る限り、コードは次のようになります。

import re

raw_patterns = [r'aaa', r'bbb', r'ccc']
patterns = [re.compile(p) for p in raw_patterns]

names = "foo", "bar"

for name in names:
    with open(name + ".log", "r") as in_fp, open(name + "_temp.log", "w") as temp:
        for line in in_fp:
            if not any(patt.match(line) for patt in patterns):
                temp.write(line)

この原理は、「自分で繰り返さない」ことを意味するDRYとして知られています。コードを繰り返していることに気付いたときはいつでも、繰り返しを抽象化することを検討できます。この場合、パターンとファイル名をリストに入れて、それらを繰り返すことができます。

-

ジェネレーター側では、それは真実です。中間ファイルを作成する必要はありません。気になる行だけを生成するオブジェクトを作成し、代わりにそれを繰り返すことができます。例えば:

from itertools import zip_longest

def informative_lines(filename):
    with open(filename) as infile:
        for line in infile:
            if not any(patt.match(line) for patt in patterns):
                yield line

paired_lines = zip_longest(informative_lines("foo.log"),
                           informative_lines("bar.log"))

for i, (line0, line1) in enumerate(paired_lines):
    if line0 != line1:
        print('mismatch at non-ignored line #', i)
        print(line0)
        print(line1)
        raise Exception("problem!")

print("hooray, files matched!")
于 2013-01-28T06:07:02.550 に答える