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

时间:2016-11-22 20:51:45

标签: python python-2.7 newline string-comparison

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

  1. 不同的行结尾('\ r \ n'vs'\ n')
  2. 文件末尾的空行数
  3. 以下是我的代码。它适用于第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
    

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

    abc\n
    

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

    abc\r\n
    

    我在每次比较之前剥离结束字符以考虑第2点。这解决了包含一系列相同行的两个文件的问题,即使一个文件以一个文件结尾,此代码也会将它们识别为“不同”空行,而另一行则不行。

    根据this answer,以'r'模式(而不是'rb')打开文件应该处理特定于操作系统的行结尾,并将它们全部读为'\ n'。这种情况没有发生。

    我如何才能将这些工作视为'\ n \ n'来处理行结尾'\ n'结尾? 我正在使用Python 2.7.12和Anaconda发行版4.2.0。

1 个答案:

答案 0 :(得分:2)

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