在python中是否存在“开箱即用”的方式来生成两个文本之间的差异列表,然后将此差异应用于一个文件以获取另一个文件,以后再进行?
我想保留文本的修订历史记录,但如果只有一个编辑的行,我不想保存每个修订版的整个文本。我查看了difflib,但我看不到如何生成一个仅包含已编辑行的列表,这些行仍可用于修改一个文本以获取另一个文本。
答案 0 :(得分:26)
您是否看过谷歌的差异匹配补丁?显然谷歌文档使用这组算法。它不仅包括diff模块,还包括补丁模块,因此您可以从旧文件和差异生成最新文件。
包含了python版本。
答案 1 :(得分:10)
difflib.unified_diff你想要吗?有一个例子here。
答案 2 :(得分:2)
AFAIK大多数差异算法使用简单的Longest Common Subsequence匹配,找到两个文本之间的共同部分,剩下的任何东西都被认为是差异。在python中编写自己的动态编程算法来实现它不应该太难,上面的维基百科页面也提供了算法。
答案 3 :(得分:2)
我已经实现了一个纯python函数来应用diff补丁来恢复任何一个输入字符串,我希望有人觉得它很有用。它使用解析Unified diff format。
import re
_hdr_pat = re.compile("^@@ -(\d+),?(\d+)? \+(\d+),?(\d+)? @@$")
def apply_patch(s,patch,revert=False):
"""
Apply unified diff patch to string s to recover newer string.
If revert is True, treat s as the newer string, recover older string.
"""
s = s.splitlines(True)
p = patch.splitlines(True)
t = ''
i = sl = 0
(midx,sign) = (1,'+') if not revert else (3,'-')
while i < len(p) and p[i].startswith(("---","+++")): i += 1 # skip header lines
while i < len(p):
m = _hdr_pat.match(p[i])
if not m: raise Exception("Cannot process diff")
i += 1
l = int(m.group(midx))-1 + (m.group(midx+1) == '0')
t += ''.join(s[sl:l])
sl = l
while i < len(p) and p[i][0] != '@':
if i+1 < len(p) and p[i+1][0] == '\\': line = p[i][:-1]; i += 2
else: line = p[i]; i += 1
if len(line) > 0:
if line[0] == sign or line[0] == ' ': t += line[1:]
sl += (line[0] != sign)
t += ''.join(s[sl:])
return t
如果有标题行("--- ...\n","+++ ...\n")
,它会跳过它们。如果我们有一个统一的差异字符串diffstr
来表示oldstr
和newstr
之间的差异:
# recreate `newstr` from `oldstr`+patch
newstr = apply_patch(oldstr, diffstr)
# recreate `oldstr` from `newstr`+patch
oldstr = apply_patch(newstr, diffstr, True)
在Python中,您可以使用 difflib (标准库的一部分)生成两个字符串的统一差异:
import difflib
_no_eol = "\ No newline at end of file"
def make_patch(a,b):
"""
Get unified string diff between two strings. Trims top two lines.
Returns empty string if strings are identical.
"""
diffs = difflib.unified_diff(a.splitlines(True),b.splitlines(True),n=0)
try: _,_ = next(diffs),next(diffs)
except StopIteration: pass
return ''.join([d if d[-1] == '\n' else d+'\n'+_no_eol+'\n' for d in diffs])
在unix上:diff -U0 a.txt b.txt
代码在GitHub上,以及使用ASCII和随机unicode字符的测试:https://gist.github.com/noporpoise/16e731849eb1231e86d78f9dfeca3abc
答案 4 :(得分:1)
它必须是python解决方案吗?
我对解决方案的第一个想法是使用版本控制系统(Subversion,Git等)或作为unix系统标准的diff
/ patch
实用程序,或者是cygwin
用于基于Windows的系统。
答案 5 :(得分:0)
您可以使用unified_diff生成文件中的差异列表。只有文件中已更改的文本才能写入新的文本文件,您可以将其用于将来的参考。 这个代码可以帮助您只写入新文件的差异。 我希望这就是你要求的!
diff = difflib.unified_diff(old_file, new_file, lineterm='')
lines = list(diff)[2:]
# linesT = list(diff)[0:3]
print (lines[0])
added = [lineA for lineA in lines if lineA[0] == '+']
with open("output.txt", "w") as fh1:
for line in added:
fh1.write(line)
print '+',added
removed = [lineB for lineB in lines if lineB[0] == '-']
with open("output.txt", "a") as fh1:
for line in removed:
fh1.write(line)
print '-',removed
在代码中使用此选项仅保存差异输出!