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)。

意义

'replace'

a[i1:i2] 应由 b[j1:j2] 替换。

'delete'

a[i1:i2] 应被删除。 请注意在此情况下 j1 == j2

'insert'

b[j1:j2] 应插入到 a[i1:i1]。 请注意在此情况下 i1 == i2

'equal'

a[i1:i2] == b[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差异计算工具的更多相关文章

  1. 比较两个文件的异同Python3 标准库difflib 实现

    比较两个文件的异同Python3 标准库difflib 实现 对于要比较两个文件特别是配置文件的差异,这种需求很常见,如果用眼睛看,真是眼睛疼. 可以使用linux命令行工具diff a_file b ...

  2. Python3 标准库

    Python3标准库 更详尽:http://blog.csdn.net/jurbo/article/details/52334345 文本 string:通用字符串操作 re:正则表达式操作 diff ...

  3. Python3标准库

    文本 1. string:通用字符串操作 2. re:正则表达式操作 3. difflib:差异计算工具 4. textwrap:文本填充 5. unicodedata:Unicode字符数据库 6. ...

  4. python023 Python3 标准库概览

    Python3 标准库概览 操作系统接口 os模块提供了不少与操作系统相关联的函数. >>> import os >>> os.getcwd() # 返回当前的工作 ...

  5. python3标准库总结

    Python3标准库 操作系统接口 os模块提供了不少与操作系统相关联的函数. ? 1 2 3 4 5 6 >>> import os >>> os.getcwd( ...

  6. 7.Python3标准库--文件系统

    ''' Python的标准库中包含大量工具,可以处理文件系统中的文件,构造和解析文件名,还可以检查文件内容. 处理文件的第一步是要确定处理的文件的名字.Python将文件名表示为简单的字符串,另外还提 ...

  7. 8.Python3标准库--数据持久存储与交换

    ''' 持久存储数据以便长期使用包括两个方面:在对象的内存中表示和存储格式之间来回转换数据,以及处理转换后数据的存储区. 标准库包含很多模块可以处理不同情况下的这两个方面 有两个模块可以将对象转换为一 ...

  8. 1.Python3标准库--前戏

    Python有一个很大的优势便是在于其拥有丰富的第三方库,可以解决很多很多问题.其实Python的标准库也是非常丰富的,今后我将介绍一下Python的标准库. 这个教程使用的书籍就叫做<Pyth ...

  9. Python3 标准库学习

    python3.5.6 官方文档  https://docs.python.org/3.5/library/index.html 1.介绍 2.内置函数 3.内置常量 3.1常数添加的 site模块 ...

随机推荐

  1. SpringBoot支持SpringData es

    ElasticSearch CRUD 1.springboot springData es spring data 是spring对数据访问抽象.这些数据可以放入db,index,nosql等包含以下 ...

  2. mysql 查询出现 "this is incompatible with sql_mode=only_full_group_by"错误解决方案,以及个人rpm方式重装所遇到的问题备份

    一.错误说明        这个错误发生在mysql 5.7 版本及以上版本会出现的问题:        mysql .7版本默认的sql配置是:sql_mode="ONLY_FULL_GR ...

  3. 最全的计算机Java毕业设计题目大全 附 源码

    本文提供数百个计算机毕设题目可以参考 并提供成品源码下载,都是从网上收集而来 源码技术全部采用java+MySQL开发,并结合了其他技术如ssm,ssh,jsp等等. 下载链接在文末! 以下是项目名称 ...

  4. Angular2的环境构筑

    1.nodejs安装   https://nodejs.org/en/download/   2.环境变量设定   Path->\node-v10.16.3-win-x64   3.在cmd下输 ...

  5. codechef Scoring Pairs

    难度 \(medium-hard\) 题意 官方中文题意 做法 很显然是可以通过计算常数个\(sum(A,B)=\sum\limits_{i=0}^A \sum\limits_{j=0}^B scor ...

  6. 数据库MySQL中关于“多表关联更新”的那些事

    在常见的sql中,我们经常在查询中进行多表关联查询,用的比较熟练.今天在开发中遇到一个实际业务场景是多表关联更新,一时不知所措.本着多学习的态度,没有直接写java代码去实现,终于把多表关联更新的sq ...

  7. 后台实战——用户登录之JWT

    https://blog.csdn.net/jackcheng_ht/article/details/52670211

  8. 如何通过 SSH/Telnet 用 root 权限登录群晖

    出于系统安全原因,对 Synology NAS 的 root 访问有限.如果您获取 root 权限,请在命令行界面中用任何属于Local Administrators群组的帐户证书登录 DSM(如Pu ...

  9. LOJ #2876. 「JOISC 2014 Day2」水壶 BFS+最小生成树+倍增LCA

    非常好的一道图论问题. 显然,我们要求城市间的最小生成树,然后查询路径最大值. 然后我们有一个非常神的处理方法:进行多源 BFS,处理出每一个城市的管辖范围. 显然,如果两个城市的管辖范围没有交集的话 ...

  10. vue登录管理

    pc端页面登录逻辑,用户未登录状态下可以访问所有页面,但是请求数据是有限的,只有在登录状态下才能访问全部数据,同时未登录状态下,可视区有遮挡元素提示登录. 主要使用的技术vue.vuex.vue-ro ...