【问题标题】:Python difflib: highlighting differences inline?Python difflib:内联突出差异?
【发布时间】:2009-04-21 19:57:32
【问题描述】:

在比较相似的行时,我想突出显示同一行的差异:

a) lorem ipsum dolor sit amet
b) lorem foo ipsum dolor amet

lorem <ins>foo</ins> ipsum dolor <del>sit</del> amet

虽然 difflib.HtmlDiff 似乎可以进行这种内联突出显示,但它会产生非常冗长的标记。

很遗憾,我找不到另一个不能逐行运行的类/方法。

我错过了什么吗? 任何指针将不胜感激!

【问题讨论】:

    标签: python diff


    【解决方案1】:

    对于您的简单示例:

    import difflib
    def show_diff(seqm):
        """Unify operations between two compared strings
    seqm is a difflib.SequenceMatcher instance whose a & b are strings"""
        output= []
        for opcode, a0, a1, b0, b1 in seqm.get_opcodes():
            if opcode == 'equal':
                output.append(seqm.a[a0:a1])
            elif opcode == 'insert':
                output.append("<ins>" + seqm.b[b0:b1] + "</ins>")
            elif opcode == 'delete':
                output.append("<del>" + seqm.a[a0:a1] + "</del>")
            elif opcode == 'replace':
                raise NotImplementedError, "what to do with 'replace' opcode?"
            else:
                raise RuntimeError, "unexpected opcode"
        return ''.join(output)
    
    >>> sm= difflib.SequenceMatcher(None, "lorem ipsum dolor sit amet", "lorem foo ipsum dolor amet")
    >>> show_diff(sm)
    'lorem<ins> foo</ins> ipsum dolor <del>sit </del>amet'
    

    这适用于字符串。您应该决定如何处理“替换”操作码。

    【讨论】:

    • 非常感谢!这正是我需要的那种样品。我不知道如何开始,但这很好地说明了这一点。再次,非常感谢!
    • +1 感谢您的示例 :) 您建议如何替换 optcodes?
    • 嗯,一个建议是在野外发现一些“替换”操作码;文档说它们可以生产,但我不记得见过任何东西(IIRC我只看到'删除'后跟'插入')。无论如何,如何处理“替换”取决于 OP。
    • docs.python.org/2/library/… 上的示例包含替换操作码。
    • 对于替换 optcodes,我只是附加了插入操作和删除值。
    【解决方案2】:

    这是受@tzot 的answer above 启发的内联差异(也兼容 Python 3):

    def inline_diff(a, b):
        import difflib
        matcher = difflib.SequenceMatcher(None, a, b)
        def process_tag(tag, i1, i2, j1, j2):
            if tag == 'replace':
                return '{' + matcher.a[i1:i2] + ' -> ' + matcher.b[j1:j2] + '}'
            if tag == 'delete':
                return '{- ' + matcher.a[i1:i2] + '}'
            if tag == 'equal':
                return matcher.a[i1:i2]
            if tag == 'insert':
                return '{+ ' + matcher.b[j1:j2] + '}'
            assert False, "Unknown tag %r"%tag
        return ''.join(process_tag(*t) for t in matcher.get_opcodes())
    

    它并不完美,例如,扩展“替换”操作码以识别替换的完整单词而不是仅仅几个不同的字母会很好,但这是一个很好的起点。

    样本输出:

    >>> a='Lorem ipsum dolor sit amet consectetur adipiscing'
    >>> b='Lorem bananas ipsum cabbage sit amet adipiscing'
    >>> print(inline_diff(a, b))
    Lorem{+  bananas} ipsum {dolor -> cabbage} sit amet{-  consectetur} adipiscing
    

    【讨论】:

      【解决方案3】:

      difflib.SequenceMatcher 将在单行上运行。您可以使用“操作码”来确定如何将第一行更改为第二行。

      【讨论】:

      • 恐怕我不太明白这一点 - 但无论如何,我会做更多的挖掘工作。谢谢。
      • 您到底想对这些差异做什么?你想要 HTML 输出还是仅仅因为 HtmlDiff 做了内联比较而使用它?
      • 虽然 HTML 输出是我的主要用例,但 HtmlDiff 的输出不允许轻松重用 - 也就是说,如果它只是插入 INS 和 DEL,则可以轻松地将其转换为进一步需要的任何内容下线。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 2017-04-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-26
      相关资源
      最近更新 更多