前言
此模块提供用于比较序列的类和函数。 例如,它可被用于比较文件,并可产生多种格式的不同文件差异信息,包括 HTML 和上下文以及统一的 diff 数据。 有关比较目录和文件,另请参阅 filecmp 模块。
Operating System: Ubuntu 22.04.4 LTS
参考文档
SequenceMatcher 的示例
以下示例比较两个字符串,并将空格视为“垃圾”:
>>> s = SequenceMatcher(lambda x: x == " ",
... "private Thread currentThread;",
... "private volatile Thread currentThread;")
ratio() 返回一个 [0, 1] 范围内的浮点数,用来衡量序列的相似度。 根据经验,ratio() 值超过 0.6 就意味着两个序列非常接近匹配:
>>> print(round(s.ratio(), 3))
0.866
如果您只对序列的匹配的位置感兴趣,则 get_matching_blocks() 就很方便:
>>> for block in s.get_matching_blocks():
... print("a[%d] and b[%d] match for %d elements" % block)
a[0] and b[0] match for 8 elements
a[8] and b[17] match for 21 elements
a[29] and b[38] match for 0 elements
请注意 get_matching_blocks() 返回的最后一个元组 (len(a), len(b), 0) 始终只用于占位,这也是元组的末尾元素(匹配的元素个数)为 0 的唯一情况。
如果你想要知道如何将第一个序列转成第二个序列,可以使用 get_opcodes():
>>> for opcode in s.get_opcodes():
... print("%6s a[%d:%d] b[%d:%d]" % opcode)
equal a[0:8] b[0:8]
insert a[8:8] b[8:17]
equal a[8:29] b[17:38]
参见
此模块中的 get_close_matches() 函数显示了如何基于 SequenceMatcher 构建简单的代码来执行有用的功能。
针对使用 SequenceMatcher 构建的小型应用程序的 简易版本控制方案。
Differ 示例
此示例比较两段文本。 首先我们设置文本为以换行符结尾的单行字符串组成的序列(这样的序列也可以通过文件型对象的 readlines() 方法来获取):
>>> text1 = ''' 1. Beautiful is better than ugly.
... 2. Explicit is better than implicit.
... 3. Simple is better than complex.
... 4. Complex is better than complicated.
... '''.splitlines(keepends=True)
>>> len(text1)
4
>>> text1[0][-1]
'\n'
>>> text2 = ''' 1. Beautiful is better than ugly.
... 3. Simple is better than complex.
... 4. Complicated is better than complex.
... 5. Flat is better than nested.
... '''.splitlines(keepends=True)
接下来我们实例化一个 Differ 对象:
>>> d = Differ()
请注意在实例化 Differ 对象时我们可以传入函数来过滤掉“垃圾”行和字符。 详情参见 Differ() 构造器说明。
最后,我们比较两个序列:
>>> result = list(d.compare(text1, text2))
result 是一个字符串列表,让我们将其美化打印出来:
>>> from pprint import pprint
>>> pprint(result)
[' 1. Beautiful is better than ugly.\n',
'- 2. Explicit is better than implicit.\n',
'- 3. Simple is better than complex.\n',
'+ 3. Simple is better than complex.\n',
'? ++\n',
'- 4. Complex is better than complicated.\n',
'? ^ ---- ^\n',
'+ 4. Complicated is better than complex.\n',
'? ++++ ^ ^\n',
'+ 5. Flat is better than nested.\n']
作为单独的多行字符串显示出来则是这样:
>>> import sys
>>> sys.stdout.writelines(result)
1. Beautiful is better than ugly.
- 2. Explicit is better than implicit.
- 3. Simple is better than complex.
+ 3. Simple is better than complex.
? ++
- 4. Complex is better than complicated.
? ^ ---- ^
+ 4. Complicated is better than complex.
? ++++ ^ ^
+ 5. Flat is better than nested.
SequenceMatcher 对象
class difflib.SequenceMatcher(isjunk=None, a='', b='', autojunk=True)
可选参数 isjunk 必须为 None (默认值) 或为接受一个序列元素并当且仅当其为应忽略的“垃圾”元素时返回真值的单参数函数。 传入 None 作为 isjunk 的值就相当于传入 lambda x: False;也就是说不忽略任何值。
ratio()
返回一个取值范围 [0, 1] 的浮点数作为序列相似性度量。
其中 T 是两个序列中元素的总数量,M 是匹配的数量,即 2.0*M / T。 请注意如果两个序列完全相同则该值为 1.0,如果两者完全不同则为 0.0。
如果 get_matching_blocks() 或 get_opcodes() 尚未被调用则此方法运算消耗较大,在此情况下你可能需要先调用 quick_ratio() 或 real_quick_ratio() 来获取一个上界。
注意: ratio() 调用的结果可能会取决于参数的顺序。 例如:
>>>> SequenceMatcher(None, 'tide', 'diet').ratio() >0.25 >>>> SequenceMatcher(None, 'diet', 'tide').ratio() >0.5
get_matching_blocks()
返回描述非重叠匹配子序列的三元组列表。 每个三元组的形式为 (i, j, n),其含义为 a[i:i+n] == b[j:j+n]。 这些三元组按 i 和 j 单调递增排列。
最后一个三元组用于占位,其值为 (len(a), len(b), 0)。 它是唯一 n == 0 的三元组。 如果 (i, j, n) 和 (i’, j’, n’) 是在列表中相邻的三元组,且后者不是列表中的最后一个三元组,则 i+n < i’ 或 j+n < j’;换句话说,相邻的三元组总是描述非相邻的相等块。
>>>> s = SequenceMatcher(None, "abxcd", "abcd") >>>> s.get_matching_blocks() >[Match(a=0, b=0, size=2), Match(a=3, b=2, size=2), Match(a=5, b=4, size=0)]
get_opcodes()
返回描述如何将 a 变为 b 的 5 元组列表,每个元组的形式为 (tag, i1, i2, j1, j2)。 在第一个元组中 i1 == j1 == 0,而在其余的元组中 i1 等于前一个元组的 i2,并且 j1 也等于前一个元组的 j2。
tag 值为字符串,其含义如下:
值 | 含意 |
---|---|
‘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] (两个子序列相同)。 |
例如:
>>>> a = "qabxcd" >>>> b = "abycdf" >>>> s = SequenceMatcher(None, a, b) >>>> for tag, i1, i2, j1, j2 in s.get_opcodes(): >... print('{:7} a[{}:{}] --> b[{}:{}] {!r:>8} --> {!r}'.format( >... tag, i1, i2, j1, j2, a[i1:i2], b[j1:j2])) >delete a[0:1] --> b[0:0] 'q' --> '' >equal a[1:3] --> b[0:2] 'ab' --> 'ab' >replace a[3:4] --> b[2:3] 'x' --> 'y' >equal a[4:6] --> b[3:5] 'cd' --> 'cd' >insert a[6:6] --> b[5:6] '' --> 'f'
Differ 对象
这个类的作用是比较由文本行组成的序列,并产生可供人阅读的差异或增量信息。 Differ 统一使用 SequenceMatcher 来完成行序列的比较以及相似(接近匹配)行内部字符序列的比较。
Differ 增量的每一行均以双字母代码打头:
双字母代码 | 含意 |
---|---|
‘- ‘ | 行为序列 1 所独有 |
‘+ ‘ | 行为序列 2 所独有 |
‘ ‘ | 行在两序列中相同 |
‘? ‘ | 行不存在于任一输入序列 |
以 ‘?’ 打头的行尝试将视线紖至行以外而不存在于任一输入序列的差异。 如果序列包含空白符,例如空格、制表或换行则这些行可能会令人感到迷惑。
结语
第二百六十五篇博文写完,开心!!!!
今天,也是充满希望的一天。