【问题标题】:Algorithm to compare two files in Python在 Python 中比较两个文件的算法
【发布时间】:2013-01-28 05:50:06
【问题描述】:

我想创建一个 python 脚本来比较一个工具生成的两个日志文件(名为 foo.logbar.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)

运行脚本后,我会得到两个文件 foo_temp.logbar_temp.log,稍后我会使用 WinMerge 手动比较它们。 以下是我的问题:

1)有什么方法可以优化我使用正则表达式的方式(我实际上是正则表达式的新手,我觉得在这方面有很多可以优化的地方)

2) 稍后当我必须添加要忽略的新模式时,我能否从用户的角度更轻松地添加新模式。 (目前我需要添加一个新模式,然后在 2 个位置进行检查——一个用于foo.log,一个用于bar.log

3) 我听说在处理巨大的文件时使用了生成器。虽然我比较的日志相对较小(最大 50MB),但我是否应该研究如何使用生成器并将它们合并到我的脚本中?

4) 与其创建foo_temp.logbar_temp.log 并使用WinMerge 进行手动检查,有没有一种方法可以在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>>

请注意,一旦我们删除了可以忽略的行,这两个文件将具有相同的模式。出于这个原因,我决定一次性删除所有可以忽略的行,然后对缩小的文件进行比较。

【问题讨论】:

    标签: regex python-3.x compare


    【解决方案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!")
    

    【讨论】:

    • 谢谢!,这让事情变得更简单:)。通过比较我的意思是,foo_temp.log 的内容应该与 bar_temp.log 的内容完全匹配。如果不是,则应引发错误。我将看看 difflib。再次感谢:)
    • 实际上,你的代码有些奇怪——现在,如果每个“被忽略”的模式都匹配,你只写一行。这不是倒退吗?
    猜你喜欢
    • 1970-01-01
    • 2015-10-30
    • 1970-01-01
    • 1970-01-01
    • 2020-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-24
    相关资源
    最近更新 更多