我想做的事情像我相信变更控制系统所做的事情一样,它们比较两个文件,并在文件更改时节省一个小差异。我一直在阅读此页面: http://docs.python.org/library/difflib.html 显然,这并没有沉入我的脑海。

我试图在下面显示的一个简单的程序中重新创建它,但是我似乎缺少的是,三角洲的包含至少与原始文件一样多。

不可能仅仅进行纯粹的变化吗?我问的原因很明显 - 节省磁盘空间。
我每次都可以保存整个代码,但是最好保存一次当前代码,然后再保存一小部分更改。

我还在试图弄清楚为什么许多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

-----显示ContextDiff ---------------------




* 5,9 **

 print "HIJ"

 print "JKL"

 print "Hello World"
  • 打印“ J =” + J

    打印“ xyz”

--- 5,9 ----

 print "HIJ"

 print "JKL"

 print "Hello World"

 print "XYZ"
  • 打印“末端”

另一个更新:

在Panvalet的过去,大型机的源管理工具,您可以创建这样的更改:

++ADD 9
   print "j=" + j 

这仅表示在第9行之后添加一条线(或行)。然后,++替换或++更新之类的单词词。http://www4.hawaii.gov/dags/icsd/ppmo/stds_web_pages/pdf/it110401.pdf

有帮助吗?

解决方案

DIFF必须包含足够的信息,以使其可以将版本修补到另一个版本中,因此,对于您的单线更改为非常小的文档的实验,存储整个文档可能会更便宜。

库功能返回迭代器,使其更容易在内存上紧张或只需要查看结果序列的一部分。在Python中还可以,因为每个迭代器都可以转换为非常短的列表 list(an_iterator) 表达。

大多数差异是在文本行上完成的,但是可以归结为符合字符,并且 difflib 可以。看一下 Differ 对象类 difflib.

整个地方的示例都采用人类友好的输出,但是差异以一种更紧凑,计算机友好的方式进行管理。另外,差异通常包含冗余信息(例如要删除的线路文本),以使修补和合并更改安全。如果您对此感到满意,可以通过自己的代码删除冗余。

我刚刚读 difflib 选择最小的战役来支持最优性,这是我不会反对的。有 众所周知 快速产生最小更改的算法。

我曾经对大约1250行Java中的最佳算法之一编码通用的扩散引擎以及一种最佳算法(JRCS)。它适用于可以比较平等的任何元素序列。如果您想构建自己的解决方案,我认为JRC的翻译/重新实现应不超过300行Python。

处理由 difflib 使其更加紧凑也是一种选择。这是一个带有三个更改的小文件(添加,更改和删除)的示例:

---  
+++  
@@ -7,0 +7,1 @@
+aaaaa
@@ -9,1 +10,1 @@
-c= 0
+c= 1
@@ -15,1 +16,0 @@
-    m = re.match(code_re, text)

补丁说什么很容易凝结到:

+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

其他提示

我还在试图弄清楚为什么许多Difflib功能返回生成器而不是列表,那里有什么优势?

好吧,请考虑一秒钟 - 如果比较文件,这些文件在理论上可以很大(并且将在实践中)很大 - 将三角洲作为列表返回,对于Exampe,意味着将完整的数据读取为存储器,这就是这不是一个明智的事情。

至于仅返回差异,使用发电机还有另一个优点 - 只需迭代三角洲,并保留您感兴趣的任何行。

如果您阅读 Difflib文档 对于不同的 - 风格的三角洲,您将看到一个段落的段落:

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

因此,如果您只需要差异,则可以通过使用 Str.Startswith

您也可以使用 difflib.context_diff 要获得仅显示更改的紧凑型三角洲。

如果您只想更改,则需要使用统一或上下文差异。您会看到较大的文件,因为它包含了它们的共同点。

返回发电机的优点是,整个过程不需要立即保存在内存中。这对于扩展非常大的文件可能很有用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top