Python Difflib delta和比较Ndiff
我想做一些我相信变更控制系统会做的事情,它们会比较两个文件,并在每次文件更改时保存一个小差异。 我一直在读这一页:显然它并没有深入我的脑海 我试着用一个简单的程序来重新创建它,如下所示, 但我似乎遗漏了一点,那就是Delta包含的内容至少和原始文件一样多,甚至更多 难道不可能实现纯粹的改变吗? 我提出这一要求的原因很明显——为了节省磁盘空间。Python Difflib delta和比较Ndiff,python,delta,difflib,Python,Delta,Difflib,我想做一些我相信变更控制系统会做的事情,它们会比较两个文件,并在每次文件更改时保存一个小差异。 我一直在读这一页:显然它并没有深入我的脑海 我试着用一个简单的程序来重新创建它,如下所示, 但我似乎遗漏了一点,那就是Delta包含的内容至少和原始文件一样多,甚至更多 难道不可能实现纯粹的改变吗? 我提出这一要求的原因很明显——为了节省磁盘空间。 我可以每次只保存整个代码块,但最好只保存当前代码一次,然后保存少量更改 我还在试图弄清楚为什么许多difflib函数返回一个生成器而不是一个列表,这有什么
我可以每次只保存整个代码块,但最好只保存当前代码一次,然后保存少量更改 我还在试图弄清楚为什么许多difflib函数返回一个生成器而不是一个列表,这有什么好处 difflib对我有用吗?还是我需要找到一个更专业、功能更丰富的软件包
# Python Difflib demo
# Author: Neal Walters
# loosely based on http://ahlawat.net/wordpress/?p=371
# 01/17/2011
# build the files here - later we will just read the files probably
file1Contents="""
for j = 1 to 10:
print "ABC"
print "DEF"
print "HIJ"
print "JKL"
print "Hello World"
print "j=" + j
print "XYZ"
"""
file2Contents = """
for j = 1 to 10:
print "ABC"
print "DEF"
print "HIJ"
print "JKL"
print "Hello World"
print "XYZ"
print "The end"
"""
filename1 = "diff_file1.txt"
filename2 = "diff_file2.txt"
file1 = open(filename1,"w")
file2 = open(filename2,"w")
file1.write(file1Contents)
file2.write(file2Contents)
file1.close()
file2.close()
#end of file build
lines1 = open(filename1, "r").readlines()
lines2 = open(filename2, "r").readlines()
import difflib
print "\n FILE 1 \n"
for line in lines1:
print line
print "\n FILE 2 \n"
for line in lines2:
print line
diffSequence = difflib.ndiff(lines1, lines2)
print "\n ----- SHOW DIFF ----- \n"
for i, line in enumerate(diffSequence):
print line
diffObj = difflib.Differ()
deltaSequence = diffObj.compare(lines1, lines2)
deltaList = list(deltaSequence)
print "\n ----- SHOW DELTALIST ----- \n"
for i, line in enumerate(deltaList):
print line
#let's suppose we store just the diffSequence in the database
#then we want to take the current file (file2) and recreate the original (file1) from it
#by backward applying the diff
restoredFile1Lines = difflib.restore(diffSequence,1) # 1 indicates file1 of 2 used to create the diff
restoreFileList = list(restoredFile1Lines)
print "\n ----- SHOW REBUILD OF FILE1 ----- \n"
# this is not showing anything!
for i, line in enumerate(restoreFileList):
print line
谢谢
更新:
contextDiffSeq = difflib.context_diff(lines1, lines2)
contextDiffList = list(contextDiffSeq)
print "\n ----- SHOW CONTEXTDIFF ----- \n"
for i, line in enumerate(contextDiffList):
print line
-----显示上下文差异-----
*5,9**
print "HIJ"
print "JKL"
print "Hello World"
- 打印“j=”+j 打印“XYZ”
- 打印“结束”
++ADD 9
print "j=" + j
意思是在第9行之后加一行。
然后有像++替换或++更新这样的单词。
如果您只想更改,您需要使用统一或上下文差异。你会看到更大的文件,因为它包含了它们共同的行 返回一个生成器的好处是,整个东西不需要立即保存在内存中。这对于扩散非常大的文件非常有用 我还想弄清楚 为什么许多difflib函数返回 生成器而不是列表,是什么 优势在哪里 好吧,想一想——如果你比较文件,这些文件在理论上(在实践中)可能相当大——以列表形式返回增量,例如,意味着将完整的数据读入内存,这不是一件明智的事情 至于只返回差分,那么,使用生成器还有另一个优势——只需迭代delta并保留您感兴趣的任何行 如果您阅读了“不同样式的增量”,您将看到一段内容如下:
Each line of a Differ delta begins with a two-letter code:
Code Meaning
'- ' line unique to sequence 1
'+ ' line unique to sequence 2
' ' line common to both sequences
'? ' line not present in either input sequence
因此,如果您只需要差异,可以使用
您还可以使用
difflib.context\u diff
获得仅显示更改的紧凑增量。diff必须包含足够的信息,以便能够将一个版本修补到另一个版本,因此,对于您对非常小的文档进行单行更改的实验,存储整个文档可能更便宜
库函数返回迭代器,以便在内存紧张或只需要查看结果序列的一部分的客户机上使用。在Python中这是可以的,因为每个迭代器都可以转换成一个带有非常短的list(一个_迭代器)
表达式的列表
大多数差异都是在文本行上进行的,但是可以一个字符一个字符地进行差异,而difflib
则可以这样做。查看difflib
中的对象类
各地的例子都使用人性化的输出,但是差异是以一种更加紧凑、计算机友好的方式在内部管理的。此外,差异通常包含冗余信息(如要删除的行的文本),以确保修补和合并更改的安全性。如果您觉得舒服的话,可以通过自己的代码删除冗余
我刚刚读到,difflib
选择了最优性,这是我不会反对的。有一些算法能够快速地产生一组最小的变化
我曾经在大约1250行Java()中编写了一个通用差分引擎和一个最佳算法。它适用于任何可以比较相等的元素序列。如果您想构建自己的解决方案,我认为JRC的翻译/重新实现应该不超过300行Python
处理difflib
生成的输出以使其更紧凑也是一种选择。这是一个小文件的示例,其中包含三个更改(添加、更改和删除):
补丁所说的内容可以很容易地浓缩为:
+7,1
aaaaa
-9,1
+10,1
c= 1
-15,1
对于您自己的示例,压缩输出为:
-8,1
+9,1
print "The end"
为了安全起见,为必须插入的行保留一个前导标记(“>”)
-8,1
+9,1
>print "The end"
这更接近你需要的吗
这是一个进行压缩的简单函数。您必须编写自己的代码才能以该格式应用修补程序,但它应该很简单
def compact_a_unidiff(s):
s = [l for l in s if l[0] in ('+','@')]
result = []
for l in s:
if l.startswith('++'):
continue
elif l.startswith('+'):
result.append('>'+ l[1:])
else:
del_cmd, add_cmd = l[3:-3].split()
del_pair, add_pair = (c.split(',') for c in (del_cmd,add_cmd))
if del_pair[1] != '0':
result.append(del_cmd)
if add_pair[1] != '0':
result.append(add_cmd)
return result
谢谢,我仍然对context_diff大于file2感到震惊。diff似乎会用它想要使用的任何内部语法说“add'print”j=“+j”at position 235”。您能否从上下文中进行.restore_diff?谢谢(请参阅上文@Karl的更新和注释)。我可能会处理一些简短的代码示例——通常是10-20行——所以我想我最好放弃diff的概念。如何将差异存储在数据库blob中?序列化它,或执行一个操作。这一切取决于目的。为什么要比较这些小文档?有多少文件?每个版本有多少修订?如果您控制了差分引擎,那么存储格式可以比一般情况下的任何修订版本更加紧凑(想想快速排序)。如果您希望在某些时间点使用/显示差异,那么对于小型文档,您可以在需要时使用
difflib
动态计算它们。一定要让我知道你的决定(我需要一个
-8,1
+9,1
>print "The end"
def compact_a_unidiff(s):
s = [l for l in s if l[0] in ('+','@')]
result = []
for l in s:
if l.startswith('++'):
continue
elif l.startswith('+'):
result.append('>'+ l[1:])
else:
del_cmd, add_cmd = l[3:-3].split()
del_pair, add_pair = (c.split(',') for c in (del_cmd,add_cmd))
if del_pair[1] != '0':
result.append(del_cmd)
if add_pair[1] != '0':
result.append(add_cmd)
return result