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模块 ...
随机推荐
- Java连载73-String方法简介
一.字符串常用的方法 package com.bjpowernode.java_learning; public class D73_StringMethodBriefIntroduction { ...
- Mac保留Python2安装Python3(Anaconda3)
作为开发人员,通常是离不开Python环境的(即便你是Java-er.Js-er.Php-er .etc.). 为何要保留Python2 Mac大多自带了python 2的环境,但是Python2在2 ...
- Windows2008R2 一键安全优化脚本
::author vim ::QQ 82996821 ::filename Windows2008R2_safe_auto_set.bat :start @echo off color 0a ...
- 【01】HTML_day01_03-HTML常用标签
typora-copy-images-to: media 第01阶段.前端基础.HTML常用标签 学习目标 理解: 相对路径三种形式 应用 排版标签 文本格式化标签 图像标签 链接 相对路径,绝对路径 ...
- 安装PHP到Ubuntu(APT)
运行环境 系统版本:Ubuntu 16.04.2 LTS 软件版本:PHP-5.6 硬件要求:无 安装过程 1.安装APT存储库 APT存储库由PPA提供. root@localhost:~# apt ...
- StringBuilder的性能
1.新创建一个对象 long startTimeA = System.currentTimeMillis(); StringBuilder sb = null; for (int i = 1 ...
- 史上最深入浅出的IT术语解读
假设你是个妹子,你有一位男朋友,与此同时你和另外一位男生暧昧不清,比朋友好,又不是恋人.你随时可以甩了现任男友,另外一位马上就能补上.这是冷备份. 假设你是个妹子,同时和两位男性在交往,两位都是你男朋 ...
- webkit 技术内幕 笔记 三
浏览器内核及特性 在浏览器中,一个很重要的模块,是将页面转变成可视化的图像结果,这就是浏览器的内核,通常被称作渲染引擎.渲染:就是根据描述或者定义构建数学模型,通过模型生成图像的过程.浏览器的渲染引擎 ...
- numpy包学习笔记
导入 import numpy as np argsort() numpy中的排序函数 返回的是数组中从小到大的索引值 from numpy import * test=[5,2,3,4,1] pri ...
- c#判断字符串是否可以转日期格式
在C#中,对格式的判断有一类专门函数,那就是TryParse.TryParse在各个不同的类型类(如int,string,DateTime)中,都是存在的.在TryParse中一般有两个参数,一个是待 ...