带行号的Python统一差异对比两个“文件”

3 投票
1 回答
2148 浏览
提问于 2025-04-18 04:15

我正在寻找一种方法,想要创建统一的差异文件,并且只显示行上下文。我尝试使用difflib.unified_diff,但没有成功。我需要在两个文件中都显示更改。

我能做到的最接近的方式是使用命令行中的diff,像这样:

/usr/bin/diff --unchanged-line-format=' %.2dn %L' --old-line-format="-%.2dn %L" --new-line-format="+%.2dn %L" file1.py file2.py

但是我只想显示行上下文,而/usr/bin/diff似乎不支持自定义行格式的上下文(例如,-U2与--line-format不兼容,会出现“冲突的输出样式选项”)。

下面是我想要实现的一个例子(输出和上面的diff一样,但只显示更改周围的1行上下文):

+01: def renamed_function() -01: def original_function(): 02: +03: """ 这里有一些很酷的东西 """ 04: 21: +22: # 这是一个新的注释 23: 85: # 输出foo()的值 +86: print "Foo is %s"%(foo()) -86: print foo() 87:

1 个回答

0

我找到了一种方法,虽然和我想做的差不多,但速度比普通的差异比较要慢。下面是我项目的完整代码,项目名叫 GitGate

def unified_diff(to_file_path, from_file_path, context=1):

    """ Returns a list of differences between two files based
    on some context. This is probably over-complicated. """

    pat_diff = re.compile(r'@@ (.[0-9]+\,[0-9]+) (.[0-9]+,[0-9]+) @@')

    from_lines = []
    if os.path.exists(from_file_path):
        from_fh = open(from_file_path,'r')
        from_lines = from_fh.readlines()
        from_fh.close()

    to_lines = []
    if os.path.exists(to_file_path):
        to_fh = open(to_file_path,'r')
        to_lines = to_fh.readlines()
        to_fh.close()

    diff_lines = []

    lines = difflib.unified_diff(to_lines, from_lines, n=context)
    for line in lines:
        if line.startswith('--') or line.startswith('++'):
            continue

        m = pat_diff.match(line)
        if m:
            left = m.group(1)
            right = m.group(2)
            lstart = left.split(',')[0][1:]
            rstart = right.split(',')[0][1:]
            diff_lines.append("@@ %s %s @@\n"%(left, right))
            to_lnum = int(lstart)
            from_lnum = int(rstart)
            continue

        code = line[0]

        lnum = from_lnum
        if code == '-':
            lnum = to_lnum
        diff_lines.append("%s%.4d: %s"%(code, lnum, line[1:]))

        if code == '-':
            to_lnum += 1
        elif code == '+':
            from_lnum += 1
        else:
            to_lnum += 1
            from_lnum += 1

    return diff_lines

撰写回答