Python difflib:如何在线高亮显示差异?
在比较相似的行时,我想在同一行上突出显示不同之处:
a) lorem ipsum dolor sit amet
b) lorem foo ipsum dolor amet
lorem <ins>foo</ins> ipsum dolor <del>sit</del> amet
虽然 difflib.HtmlDiff 看起来可以做到这种行内高亮,但它生成的标记代码非常冗长。
不幸的是,我没有找到其他的类或方法,它们不是逐行操作的。
我是不是漏掉了什么?
任何建议都非常感谢!
3 个回答
3
difflib.SequenceMatcher 是一个可以处理单行文本的工具。你可以利用它提供的“操作码”来找出如何修改第一行,使它变成第二行。
9
这里有一个内联的差异比较工具,灵感来自@tzot的上面的回答(也兼容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
54
对于你的简单例子:
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'
这个是可以用在字符串上的。你需要决定一下“替换”操作该怎么处理。