【问题标题】:Compare 2 files line by line ignoring newline differences逐行比较 2 个文件,忽略换行符差异
【发布时间】:2017-04-06 16:34:52
【问题描述】:

我正在使用 Python 2.7 逐行比较两个文本文件,忽略:

  1. 不同的行尾('\r\n' vs '\n')
  2. 文件末尾的空行数

下面是我的代码。它适用于第 2 点,但不适用于第 1 点。我正在比较的文件可能很大,所以我正在逐行阅读它们。请不要推荐 zip 或类似的库。

def compare_files_by_line(fpath1, fpath2):
    # notice the opening mode 'r'
    with open(fpath1, 'r') as file1, open(fpath2, 'r') as file2:
        file1_end = False
        file2_end = False
        found_diff = False
        while not file1_end and not file2_end and not found_diff:
            try:
                # reasons for stripping explained below
                f1_line = next(file1).rstrip('\n')
            except StopIteration:
                f1_line = None
                file1_end = True
            try:
                f2_line = next(file2).rstrip('\n')
            except StopIteration:
                f2_line = None
                file2_end = True

            if f1_line != f2_line:
                if file1_end or file2_end:
                    if not (f1_line == '' or f2_line == ''):
                        found_diff = True
                        break
                else:
                    found_diff = True
                    break

    return not found_diff

您可以测试此代码未能满足第 1 点。通过为其提供 2 个文件,其中一个文件的行以 UNIX 换行符结尾

abc\n

另一个以 Windows 换行符结尾的行

abc\r\n

我在每次比较之前去掉了结束行字符以说明第 2 点。这解决了两个文件包含一系列相同行的问题,即使一个文件以空行,而另一行没有。

根据this answer,以“r”模式(而不是“rb”)打开文件应该注意特定于操作系统的行尾,并将它们全部读取为“\n”。这不会发生。

我怎样才能使这项工作将行尾 '\r\n' 视为 '\n' 结尾?
我正在使用 Python 2.7.12 和 Anaconda 发行版 4.2.0。

【问题讨论】:

    标签: python python-2.7 newline string-comparison


    【解决方案1】:

    在打开的'r' 选项上,documentation 表示:

    The default is to use text mode, which may convert '\n' characters
    to a platform-specific representation on writing and back on
    reading. Thus, when opening a binary file, you should append 'b' to
    the mode value to open the file in binary mode, which will improve portability.
    

    所以它是否转换结束符是特定于实现的,你不应该依赖它。 (但在二进制文件中,这可能会导致一些问题,因此使用 'b' 选项)

    我们可以通过将rstrip 函数更改为f1_line.rstrip('\r\n') 来解决这个问题。这样,所有平台上的行尾都会被强制删除。

    我在下面创建了您的程序的简化版本:

    from itertools import izip
    
    def compare_files(fpath1, fpath2):
        with open(fpath1, 'r') as file1, open(fpath2, 'r') as file2:
            for linef1, linef2 in izip(file1, file2):
                linef1 = linef1.rstrip('\r\n')
                linef2 = linef2.rstrip('\r\n')
    
                if linef1 != linef2:
                    return False
            return next(file1, None) == None and next(file2, None) == None
    

    【讨论】:

    • 请不要将这两个文件压缩在一起。它看起来更好,但我更喜欢避免使用大文件。我知道也有 izip,但请保持基本的。
    • 你确定 '\r\n' 对 '\r\n' 和 '\n' 都有效吗?
    • 你可以在 REPL 中自己测试它。另外我个人更喜欢拉链,但是,你说得对,izip 会更好。
    • 有效!从来没想过rstrip会这样工作!它也适用于“\n\r”!谢谢大佬!
    • 顺便说一句,在 'r' 模式下打开文件仍然会保留特定于操作系统的端线是否正常?
    猜你喜欢
    • 2022-10-17
    • 2013-03-14
    • 1970-01-01
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-31
    相关资源
    最近更新 更多