逐行比较 2 个文件,忽略换行差异

Compare 2 files line by line ignoring newline differences

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

  1. 不同的行结尾('\r\n' 与 '\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 点,我在每次比较前去掉了结束符。这解决了两个文件包含一系列相同行的问题,此代码会将它们识别为 "not different",即使一个文件以空行结尾,而另一行没有。

根据 this answer,以 'r' 模式(而不是 'rb')打开文件应该注意 OS-特定的行结尾并读取它们作为'\n'。这不会发生。

我怎样才能将行结尾“\r\n”当作“\n”结尾来处理?
我正在使用 Python 2.7.12 和 Anaconda 发行版 4.2.0.

在打开的'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