Python3标准库:difflib差异计算工具
1. difflib差异计算工具
此模块提供用于比较序列的类和函数。 例如,它可以用于比较文件,并可以产生各种格式的不同信息,包括HTML和上下文以及统一格式的差异点。有关目录和文件的比较,请参见filecmp模块。
class difflib.SequenceMatcher(None,s1,s2)
这是一个灵活的类,可用于比较任何类型的序列对,只要序列元素为 hashable 对象。 其基本算法要早于由 Ratcliff 和 Obershelp 于 1980 年代末期发表并以“格式塔模式匹配”的夸张名称命名的算法,并且更加有趣一些。 其思路是找到不包含“垃圾”元素的最长连续匹配子序列;所谓“垃圾”元素是指其在某种意义上没有价值,例如空白行或空白符。 (处理垃圾元素是对 Ratcliff 和 Obershelp 算法的一个扩展。) 然后同样的思路将递归地应用于匹配序列的左右序列片段。 这并不能产生最小编辑序列,但确实能产生在人们看来“正确”的匹配。
1.1 比较文本体
differ类用于处理文本行序列,并生成人类可读的差异(deltas)或更改指令各行中的差异。differ生成的默认输出与unix下的diff命令行工具类似,包括表的原始输入值(包含共同的值),以及指示做了哪些更改的标记数据。
有 - 前缀的行在
第一个序列中,而非第二个序列。有 + 前缀的行在第二个序列中,而非第一个序列。
如果某一行的版本之间存在增量差异,那么会使用一个加 ? 前缀以突出在新版本中的更改。
如果一行未改变,则会打印输出,而且其左列有一个额外的空格,使它与其有差异的输出对齐。
将文本传入compare()之前先将其分解为由单个文本行构成的序列,与传入串相比,这样可以生成更可读的输出。
import difflib text1 = """Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Integer eu lacus accumsan arcu fermentum euismod. Donec
pulvinar porttitor tellus. Aliquam venenatis. Donec facilisis
pharetra tortor. In nec mauris eget magna consequat
convalis. Nam sed sem vitae odio pellentesque interdum. Sed
consequat viverra nisl. Suspendisse arcu metus, blandit quis,
rhoncus ac, pharetra eget, velit. Mauris urna. Morbi nonummy
molestie orci. Praesent nisi elit, fringilla ac, suscipit non,
tristique vel, mauris. Curabitur vel lorem id nisl porta
adipiscing. Suspendisse eu lectus. In nunc. Duis vulputate
tristique enim. Donec quis lectus a justo imperdiet tempus.""" text1_lines = text1.splitlines() text2 = """Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Integer eu lacus accumsan arcu fermentum euismod. Donec
pulvinar, porttitor tellus. Aliquam venenatis. Donec facilisis
pharetra tortor. In nec mauris eget magna consequat
convalis. Nam cras vitae mi vitae odio pellentesque interdum. Sed
consequat viverra nisl. Suspendisse arcu metus, blandit quis,
rhoncus ac, pharetra eget, velit. Mauris urna. Morbi nonummy
molestie orci. Praesent nisi elit, fringilla ac, suscipit non,
tristique vel, mauris. Curabitur vel lorem id nisl porta
adipiscing. Duis vulputate tristique enim. Donec quis lectus a
justo imperdiet tempus. Suspendisse eu lectus. In nunc.""" text2_lines = text2.splitlines() d = difflib.Differ()
diff = d.compare(text1_lines, text2_lines)
print('\n'.join(diff))
结果:

示例数据中两个文本段的开始部分是一样的,所以第一行会直接打印而没有任何额外标注。

数据的第三行有变化,修改后的文本中包含有一个逗号。这两个版本的数据行都会打印,而且第五行上的额外信息会显示文本中哪一列有修改,这里显示增加了 , 字符。

输出中接下来几行显示删除了一个多余的空格。

接下来有一个更复杂的改变,其替换了一个短语中的多个单词。

段落中最后一句变化最大,所以表示差异时完全删除了老版本,增加了新版本。

ndiff()函数生成的输出基本上相同,通过特别“加工”来处理文本数据,并删除输入中的“噪声”。
differ()类会显示所有输入行,统一差异格式(unified diff)则不同,它只包含有修改的文本行和一些上下文。unified_diff()函数会生成这种输出。
import difflib text1 = """Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Integer eu lacus accumsan arcu fermentum euismod. Donec
pulvinar porttitor tellus. Aliquam venenatis. Donec facilisis
pharetra tortor. In nec mauris eget magna consequat
convalis. Nam sed sem vitae odio pellentesque interdum. Sed
consequat viverra nisl. Suspendisse arcu metus, blandit quis,
rhoncus ac, pharetra eget, velit. Mauris urna. Morbi nonummy
molestie orci. Praesent nisi elit, fringilla ac, suscipit non,
tristique vel, mauris. Curabitur vel lorem id nisl porta
adipiscing. Suspendisse eu lectus. In nunc. Duis vulputate
tristique enim. Donec quis lectus a justo imperdiet tempus.""" text1_lines = text1.splitlines() text2 = """Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Integer eu lacus accumsan arcu fermentum euismod. Donec
pulvinar, porttitor tellus. Aliquam venenatis. Donec facilisis
pharetra tortor. In nec mauris eget magna consequat
convalis. Nam cras vitae mi vitae odio pellentesque interdum. Sed
consequat viverra nisl. Suspendisse arcu metus, blandit quis,
rhoncus ac, pharetra eget, velit. Mauris urna. Morbi nonummy
molestie orci. Praesent nisi elit, fringilla ac, suscipit non,
tristique vel, mauris. Curabitur vel lorem id nisl porta
adipiscing. Duis vulputate tristique enim. Donec quis lectus a
justo imperdiet tempus. Suspendisse eu lectus. In nunc.""" text2_lines = text2.splitlines() diff = difflib.unified_diff(
text1_lines,
text2_lines,
lineterm='',
)
print('\n'.join(diff))
lineterm参数用来告诉unified_diff()不必为它返回的控制行追加换行符,因为输入行不包括这些换行符。打印时所有行都会增加换行符。对于很多常用版本控制工具的用户来说,输出看上去应该很熟悉。

使用context_diff()会产生类似的可续输出。
1.2 无用数据
所有生成差异序列的函数都会接受一些参数来指示应当忽略哪些行,以及要忽略一行中的哪些字符。例如,这些参数可用于跳过文件两个版本中的标记或空白符改变。
from difflib import SequenceMatcher def show_results(match):
print(' a = {}'.format(match.a))
print(' b = {}'.format(match.b))
print(' size = {}'.format(match.size))
i, j, k = match
print(' A[a:a+size] = {!r}'.format(A[i:i + k]))
print(' B[b:b+size] = {!r}'.format(B[j:j + k])) A = " abcd"
B = "abcd abcd" print('A = {!r}'.format(A))
print('B = {!r}'.format(B)) print('\nWithout junk detection:')
s1 = SequenceMatcher(None, A, B)
match1 = s1.find_longest_match(0, len(A), 0, len(B))
show_results(match1) print('\nTreat spaces as junk:')
s2 = SequenceMatcher(lambda x: x == " ", A, B)
match2 = s2.find_longest_match(0, len(A), 0, len(B))
show_results(match2)
默认differ不会显式地忽略任何行或字符,但会依赖SequenceMatcher的能力检测噪声。ndiff()的默认行为是忽略空格和制表符。

1.3 比较任意类型
SequenceMatcher类可以比较任意类型的两个序列,只要它们的值是可散列的。这个类使用一个算法来标识序列中最长的连续匹配块,并删除对实际数据没有贡献的无用值。
函数get_opcodes()返回一个指令列表来修改第一个序列,使它与第二个序列匹配。这些指令被编码为5元素元组,包括一个字符串指令(“操作码”)和序列的两对开始及结束索引(表示为i1、i2、j1和j2)。
|
值 |
意义 |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
import difflib s1 = [1, 2, 3, 5, 6, 4]
s2 = [2, 3, 5, 4, 6, 1] print('Initial data:')
print('s1 =', s1)
print('s2 =', s2)
print('s1 == s2:', s1 == s2)
print() matcher = difflib.SequenceMatcher(None, s1, s2)
for tag, i1, i2, j1, j2 in reversed(matcher.get_opcodes()): if tag == 'delete':
print('Remove {} from positions [{}:{}]'.format(
s1[i1:i2], i1, i2))
print(' before =', s1)
del s1[i1:i2] elif tag == 'equal':
print('s1[{}:{}] and s2[{}:{}] are the same'.format(
i1, i2, j1, j2)) elif tag == 'insert':
print('Insert {} from s2[{}:{}] into s1 at {}'.format(
s2[j1:j2], j1, j2, i1))
print(' before =', s1)
s1[i1:i2] = s2[j1:j2] elif tag == 'replace':
print(('Replace {} from s1[{}:{}] '
'with {} from s2[{}:{}]').format(
s1[i1:i2], i1, i2, s2[j1:j2], j1, j2))
print(' before =', s1)
s1[i1:i2] = s2[j1:j2] print(' after =', s1, '\n') print('s1 == s2:', s1 == s2)
这个例子比较了两个整数列表,并使用get_opcodes()得出将原列表转换为新列表的指令。这里以逆序应用所做的修改,以便增加和删除元素之后列表索引仍是正确的。

SequenceMatcher用于处理定制类以及内置类型,前提是它们必须是可散列的。
Python3标准库:difflib差异计算工具的更多相关文章
- 比较两个文件的异同Python3 标准库difflib 实现
比较两个文件的异同Python3 标准库difflib 实现 对于要比较两个文件特别是配置文件的差异,这种需求很常见,如果用眼睛看,真是眼睛疼. 可以使用linux命令行工具diff a_file b ...
- Python3 标准库
Python3标准库 更详尽:http://blog.csdn.net/jurbo/article/details/52334345 文本 string:通用字符串操作 re:正则表达式操作 diff ...
- Python3标准库
文本 1. string:通用字符串操作 2. re:正则表达式操作 3. difflib:差异计算工具 4. textwrap:文本填充 5. unicodedata:Unicode字符数据库 6. ...
- python023 Python3 标准库概览
Python3 标准库概览 操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作 ...
- python3标准库总结
Python3标准库 操作系统接口 os模块提供了不少与操作系统相关联的函数. ? 1 2 3 4 5 6 >>> import os >>> os.getcwd( ...
- 7.Python3标准库--文件系统
''' Python的标准库中包含大量工具,可以处理文件系统中的文件,构造和解析文件名,还可以检查文件内容. 处理文件的第一步是要确定处理的文件的名字.Python将文件名表示为简单的字符串,另外还提 ...
- 8.Python3标准库--数据持久存储与交换
''' 持久存储数据以便长期使用包括两个方面:在对象的内存中表示和存储格式之间来回转换数据,以及处理转换后数据的存储区. 标准库包含很多模块可以处理不同情况下的这两个方面 有两个模块可以将对象转换为一 ...
- 1.Python3标准库--前戏
Python有一个很大的优势便是在于其拥有丰富的第三方库,可以解决很多很多问题.其实Python的标准库也是非常丰富的,今后我将介绍一下Python的标准库. 这个教程使用的书籍就叫做<Pyth ...
- Python3 标准库学习
python3.5.6 官方文档 https://docs.python.org/3.5/library/index.html 1.介绍 2.内置函数 3.内置常量 3.1常数添加的 site模块 ...
随机推荐
- 《C++Primer》第五版习题答案--第五章【学习笔记】
<C++Primer>第五版习题答案--第五章[学习笔记] ps:答案是个人在学习过程中书写,可能存在错漏之处,仅作参考. 作者:cosefy Date: 2020/1/15 第五章:语句 ...
- ASP.NET Core DI概述
众所周知,ASP.NET Core有一个DI框架,应用程序启动时初始化. 预定义依赖 1: IApplicationBuilder:提供了配置应用程序的请求管道机制 2:ILoggerFactory: ...
- Golang模块之HTTP
HTTP客户端和服务端 Go语言中内置net/http包提供了HTTP客户端和服务端的实现 HTTP服务端 package main import ( "encoding/json" ...
- Java-利用位数猜年龄
题目: 美国数学家维纳(N.Wiener)智力早熟,11岁就上了大学.他曾在1935~1936年应邀来中国清华大学讲学.一次,他参加某个重要会议,年轻的脸孔引人注目.于是有人询问他的年龄,他回答说:“ ...
- spring cloud微服务快速教程之(九) Spring Cloud Alibaba--sentinel-限流、熔断降级
0.前言 sentinel的限流.降级功能强大,可以在控制面板中任意制定规则,然后推送到微服务中: 可以根据URL单独制定规则,也可以根据资源名批量制定规则: 需要注意的地方是:1.GITHUB文件在 ...
- python3-cookbook笔记:第四章 迭代器与生成器
python3-cookbook中每个小节以问题.解决方案和讨论三个部分探讨了Python3在某类问题中的最优解决方式,或者说是探讨Python3本身的数据结构.函数.类等特性在某类问题上如何更好地使 ...
- 使用pem连接服务器
后台同学甩给你一个pem文件,username@IP后如何链接服务器 准备:ssh客户端 例子xshell 文件->新建->主机(连接界面主机输入框输入IP)->点击用户身份-> ...
- python-flask模块注入(SSTI)
前言: 第一次遇到python模块注入是做ctf的时候,当时并没有搞懂原理所在,看了网上的资料,这里做一个笔记. flask基础: 先看一段python代码: from flask import fl ...
- MobaXterm监控服务器的资源(CPU/RAM/Network/disk/...) 使用情况
我使用服务器的时候比较喜欢随时查看的服务器资源使用情况,比如内存,CPU,网速,磁盘使用等情况,一次偶然的机会发现了MobaXterm提供有这项功能,在会话窗口底部: (完整窗口) 如果你发现你的会话 ...
- ssh 或 putty 连接linux报错解决方法
由于当天多次输入错误密码,ssh和putty就连接不上了,纠结了很久解决问题 ssh连接提示错误:server unexpectedly closed network connection putty ...