python3从零学习-5.1.4、对比模块Difflib
此模块提供用于比较序列的类和函数。 例如,它可以用于比较文件,并可以产生各种格式的不同信息,包括 HTML 和上下文以及统一格式的差异点。 有关目录和文件的比较,请参见 filecmp 模块。
class difflib.SequenceMatcher
这是一个灵活的类,可用于比较任何类型的序列对,只要序列元素为 hashable 对象。 其基本算法要早于由 Ratcliff 和 Obershelp 于 1980 年代末期发表并以“格式塔模式匹配”的夸张名称命名的算法,并且更加有趣一些。 其思路是找到不包含“垃圾”元素的最长连续匹配子序列;所谓“垃圾”元素是指其在某种意义上没有价值,例如空白行或空白符。 (处理垃圾元素是对 Ratcliff 和 Obershelp 算法的一个扩展。) 然后同样的思路将递归地应用于匹配序列的左右序列片段。 这并不能产生最小编辑序列,但确实能产生在人们看来“正确”的匹配。
耗时: 基本 Ratcliff-Obershelp 算法在最坏情况下为立方时间而在一般情况下为平方时间。 SequenceMatcher 在最坏情况下为平方时间而在一般情况下的行为受到序列中有多少相同元素这一因素的微妙影响;在最佳情况下则为线性时间。
自动垃圾启发式计算: SequenceMatcher 支持使用启发式计算来自动将特定序列项视为垃圾。 这种启发式计算会统计每个单独项在序列中出现的次数。 如果某一项(在第一项之后)的重复次数超过序列长度的 1% 并且序列长度至少有 200 项,该项会被标记为“热门”并被视为序列匹配中的垃圾。 这种启发式计算可以通过在创建 SequenceMatcher 时将 autojunk 参数设为 False 来关闭。
3.2 新版功能: autojunk 形参。
class difflib.Differ
这个类的作用是比较由文本行组成的序列,并产生可供人阅读的差异或增量信息。 Differ 统一使用 SequenceMatcher 来完成行序列的比较以及相似(接近匹配)行内部字符序列的比较。
Differ 增量的每一行均以双字母代码打头:
双字母代码含义
'- '行为序列 1 所独有
'+ '行为序列 2 所独有
' '行在两序列中相同
'? '行不存在于任一输入序列
以 ‘?’ 打头的行尝试将视线引至行以外而不存在于任一输入序列的差异。 如果序列包含制表符则这些行可能会令人感到迷惑。
class difflib.HtmlDiff
这个类可用于创建 HTML 表格(或包含表格的完整 HTML 文件)以并排地逐行显示文本比较,行间与行外的更改将突出显示。 此表格可以基于完全或上下文差异模式来生成。
这个类的构造函数:
__init__(tabsize=8, wrapcolumn=None, linejunk=None, charjunk=IS_CHARACTER_JUNK)
初始化 HtmlDiff 的实例。
tabsize 是一个可选关键字参数,指定制表位的间隔,默认值为 8。
wrapcolumn 是一个可选关键字参数,指定行文本自动打断并换行的列位置,默认值为 None 表示不自动换行。
linejunk 和 charjunk 均是可选关键字参数,会传入 ndiff() (被 HtmlDiff 用来生成并排显示的 HTML 差异)。 请参阅 ndiff() 文档了解参数默认值及其说明。
下列是公开的方法
make_file(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5, *, charset='utf-8')
比较 fromlines 和 tolines (字符串列表) 并返回一个字符串,表示一个完整 HTML 文件,其中包含各行差异的表格,行间与行外的更改将突出显示。
fromdesc 和 todesc 均是可选关键字参数,指定来源/目标文件的列标题字符串(默认均为空白字符串)。
context 和 numlines 均是可选关键字参数。 当只要显示上下文差异时就将 context 设为 True,否则默认值 False 为显示完整文件。 numlines 默认为 5。 当 context 为 True 时 numlines 将控制围绕突出显示差异部分的上下文行数。 当 context 为 False 时 numlines 将控制在使用 “next” 超链接时突出显示差异部分之前所显示的行数(设为零则会导致 “next” 超链接将下一个突出显示差异部分放在浏览器顶端,不添加任何前导上下文)。
在 3.5 版更改: 增加了 charset 关键字参数。 HTML 文档的默认字符集从 'ISO-8859-1' 更改为 'utf-8'。
make_table(fromlines, tolines, fromdesc='', todesc='', context=False, numlines=5)
比较 fromlines 和 tolines (字符串列表) 并返回一个字符串,表示一个包含各行差异的完整 HTML 表格,行间与行外的更改将突出显示。
此方法的参数与 make_file() 方法的相同。
Tools/scripts/diff.py 是这个类的命令行前端,其中包含一个很好的使用示例。
difflib.context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n')
比较 a 和 b (字符串列表);返回上下文差异格式的增量信息 (一个产生增量行的 generator)。
所谓上下文差异是一种只显示有更改的行再加几个上下文行的紧凑形式。 更改被显示为之前/之后的样式。 上下文行数由 n 设定,默认为三行。
默认情况下,差异控制行(以 *** or --- 表示)是通过末尾换行符来创建的。 这样做的好处是从 io.IOBase.readlines() 创建的输入将得到适用于 io.IOBase.writelines() 的差异信息,因为输入和输出都带有末尾换行符。
对于没有末尾换行符的输入,应将 lineterm 参数设为 "",这样输出内容将统一不带换行符。
上下文差异格式通常带有一个记录文件名和修改时间的标头。 这些信息的部分或全部可以使用字符串 fromfile, tofile, fromfiledate 和 tofiledate 来指定。 修改时间通常以 ISO 8601 格式表示。 如果未指定,这些字符串默认为空。
>>>s1=['bacon\n','eggs\n','ham\n','guido\n']
>>>s2=['python\n','eggy\n','hamster\n','guido\n']
>>>sys.stdout.writelines(context_diff(s1, s2, fromfile='before.py', tofile='after.py'))
***before.py
---after.py
***************
*** 1,4 ****
! bacon
! eggs
! ham
guido
--- 1,4 ----
! python
! eggy
! hamster
guido
请参阅 difflib 的命令行接口 获取更详细的示例。
difflib.get_close_matches(word, possibilities, n=3, cutoff=0.6)
返回由最佳“近似”匹配构成的列表。 word 为一个指定目标近似匹配的序列(通常为字符串),possibilities 为一个由用于匹配 word 的序列构成的列表(通常为字符串列表)。
可选参数 n (默认为 3) 指定最多返回多少个近似匹配; n 必须大于 0.
可选参数 cutoff (默认为 0.6) 是一个 [0, 1] 范围内的浮点数。 与 word 相似度得分未达到该值的候选匹配将被忽略。
候选匹配中(不超过 n 个)的最佳匹配将以列表形式返回,按相似度得分排序,最相似的排在最前面。
>>>get_close_matches('appel', ['ape','apple','peach','puppy'])
['apple', 'ape']
>>>importkeyword
>>>get_close_matches('wheel', keyword.kwlist)
['while']
>>>get_close_matches('pineapple', keyword.kwlist)
[]
>>>get_close_matches('accept', keyword.kwlist)
['except']
difflib.ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK)
比较 a 和 b (字符串列表);返回 Differ 形式的增量信息 (一个产生增量行的 generator)。
可选关键字形参 linejunk 和 charjunk 均为过滤函数 (或为 None):
linejunk: 此函数接受单个字符串参数,如果其为垃圾字符串则返回真值,否则返回假值。 默认为 None。 此外还有一个模块层级的函数 IS_LINE_JUNK(),它会过滤掉没有可见字符的行,除非该行添加了至多一个井号符 ('#') – 但是下层的 SequenceMatcher 类会动态分析哪些行的重复频繁到足以形成噪音,这通常会比使用此函数的效果更好。
charjunk: 此函数接受一个字符(长度为 1 的字符串),如果其为垃圾字符则返回真值,否则返回假值。 默认为模块层级的函数 IS_CHARACTER_JUNK(),它会过滤掉空白字符(空格符或制表符;但包含换行符可不是个好主意!)。
Tools/scripts/ndiff.py 是这个函数的命令行前端。
>>>diff=ndiff('one\ntwo\nthree\n'.splitlines(keepends=True),
... 'ore\ntree\nemu\n'.splitlines(keepends=True))
>>>print(''.join(diff), end="")
- one
? ^
+ ore
? ^
- two
- three
? -
+ tree
+ emu
difflib.restore(sequence, which)
返回两个序列中产生增量的那一个。
给出一个由 Differ.compare() 或 ndiff() 产生的 序列,提取出来自文件 1 或 2 (which 形参) 的行,去除行前缀。
示例:
>>>diff=ndiff('one\ntwo\nthree\n'.splitlines(keepends=True),
... 'ore\ntree\nemu\n'.splitlines(keepends=True))
>>>diff=list(diff)# materialize the generated delta into a list
>>>print(''.join(restore(diff,1)), end="")
one
two
three
>>>print(''.join(restore(diff,2)), end="")
ore
tree
emu
difflib.unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n')
比较 a 和 b (字符串列表);返回统一差异格式的增量信息 (一个产生增量行的 generator)。
所以统一差异是一种只显示有更改的行再加几个上下文行的紧凑形式。 更改被显示为内联的样式(而不是分开的之前/之后文本块)。 上下文行数由 n 设定,默认为三行。
默认情况下,差异控制行 (以 ---, +++ 或 @@ 表示) 是通过末尾换行符来创建的。 这样做的好处是从 io.IOBase.readlines() 创建的输入将得到适用于 io.IOBase.writelines() 的差异信息,因为输入和输出都带有末尾换行符。
对于没有末尾换行符的输入,应将 lineterm 参数设为 "",这样输出内容将统一不带换行符。
上下文差异格式通常带有一个记录文件名和修改时间的标头。 这些信息的部分或全部可以使用字符串 fromfile, tofile, fromfiledate 和 tofiledate 来指定。 修改时间通常以 ISO 8601 格式表示。 如果未指定,这些字符串默认为空。
>>>s1=['bacon\n','eggs\n','ham\n','guido\n']
>>>s2=['python\n','eggy\n','hamster\n','guido\n']
>>>sys.stdout.writelines(unified_diff(s1, s2, fromfile='before.py', tofile='after.py'))
---before.py
+++after.py
@@ -1,4 +1,4 @@
-bacon
-eggs
-ham
+python
+eggy
+hamster
guido
请参阅 difflib 的命令行接口 获取更详细的示例。
difflib.diff_bytes(dfunc, a, b, fromfile=b'', tofile=b'', fromfiledate=b'', tofiledate=b'', n=3, lineterm=b'\n')
使用 dfunc 比较 a 和 b (字节串对象列表);产生以 dfunc 所返回格式表示的差异行列表(也是字节串)。 dfunc 必须是可调用对象,通常为 unified_diff() 或 context_diff()。
允许你比较编码未知或不一致的数据。 除 n 之外的所有输入都必须为字节串对象而非字符串。 作用方式为无损地将所有输入 (除 n 之外) 转换为字符串,并调用 dfunc(a, b, fromfile, tofile, fromfiledate, tofiledate, n, lineterm)。 dfunc 的输出会被随即转换回字节串,这样你所得到的增量行将具有与 a 和 b 相同的未知/不一致编码。
3.5 新版功能.
difflib.IS_LINE_JUNK(line)
Return true for ignorable lines. The line line is ignorable if line is blank or contains a single '#', otherwise it is not ignorable. Used as a default for parameter linejunk in ndiff() in older versions.
difflib.IS_CHARACTER_JUNK(ch)
Return true for ignorable characters. The character ch is ignorable if ch is a space or tab, otherwise it is not ignorable. Used as a default for parameter charjunk in ndiff().