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模块 ...
随机推荐
- B样条曲线方程和C++实现
功能:根据参数u值和k(大小为阶数值)与节点矢量,计算第i个k次B样条基数 输入参数: u—参数值:k—大小值为阶数:i—第i个k次B样条的支撑区间左端节点的下标:aNode为节点向量. 输出参数:返 ...
- python选课系统作业
# 选课系统# 角色:学校.学员.课程.讲师# 要求:# 1. 创建北京.上海 2 所学校# 2. 创建linux , python , go 3个课程 , linux\py 在北京开, go 在上海 ...
- 浅谈 vue-loader---合格前端
什么是 vue-loader? vue-loader 是一个 webpack 的 loader,它允许你以一种名为单文件组件的格式撰写 Vue 组件. 如何使用? 1. 安装 npm install ...
- MySQL基础篇(02):从五个维度出发,审视表结构设计
本文源码:GitHub·点这里 || GitEE·点这里 一.数据场景 1.表结构简介 任何工具类的东西都是为了解决某个场景下的问题,比如Redis缓存系统热点数据,ClickHouse解决海量数据的 ...
- 洛谷P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib 使用四种算法
洛谷P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib 水题一道…… 题目描述 农民约翰的母牛总是产生最好的肋骨.你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们. ...
- QPixmap和QImage
1.QPixmap QPixmap的设计本来就是用来加速显示,用paint绘图时用QPixmap会比其他类的效果好很多.一般小图片用QPixmap. 2.QImage 依赖软件,直接像素访问,适合大图 ...
- 转: Laravel的数据库迁移 介绍的比较清晰
原文: https://blog.sbot.io/articles/12/Laravel-数据库迁移(Database-Migrations)操作实例 很多人可能在学习Laravel框架的时候,对La ...
- 极其实用的JS单行代码
个人博客 地址:https://www.wenhaofan.com/a/20190629211647 1.强制布尔值 要将变量强制转换为布尔值而不更改其值: const myBoolean = !! ...
- C#加密与解密(DES\RSA)学习笔记
本笔记摘抄自:https://www.cnblogs.com/skylaugh/archive/2011/07/12/2103572.html,记录一下学习过程以备后续查用. 数据加密技术是网络中最基 ...
- Java细节1--输入关闭
import java.util.Scanner; public class Demo01 { public static void main(String[] args) { Scanner sc= ...