文本相似度-python之difflib库SequenceMatcher类
官方文档链接:https://docs.python.org/zh-cn/3/library/difflib.html官方文档这直译也太拗口了,下面内容为阅读官方文档的总结:内涵:difflib模块提供用于比较序列的类和函数。 例如,它可被用于比较文件,并可产生多种格式的不同文件差异信息,包括 HTML 和上下文以及统一的 diff 数据。 有关比较目录和文件,另请参阅filecmp模块。这个库有
官方文档链接:https://docs.python.org/zh-cn/3/library/difflib.html
官方文档这直译也太拗口了,下面内容为阅读官方文档的总结,橙色文字为本人批注:
内涵:difflib模块提供用于比较序列的类和函数。 例如,它可被用于比较文件,并可产生多种格式的不同文件差异信息,包括 HTML 和上下文以及统一的 diff 数据。 有关比较目录和文件,另请参阅 filecmp
模块。
这个库有两个类,SequenceMatcher和Differ。SequenceMatcher(序列匹配,可以理解成功能比较丰富的子串匹配),而Differ(差异)重在比较两个文本的差异。
前言:由于我阅读这个文档是为了找出文本中与另一些短语相似的部分,我只记录SequenceMatcher部分
目录
构造函数SequenceMatcher(isjunk=None, a='', b='', autojunk=True)
2.find_longest_match(alo=0, ahi=None, blo=0, bhi=None)
构造函数SequenceMatcher
(isjunk=None, a='', b='', autojunk=True)
可选参数 isjunk 必须为 None
(默认值) 或为接受一个序列元素并当且仅当其为应忽略的“垃圾”元素时返回真值的单参数函数。 传入 None
作为 isjunk 的值就相当于传入 lambda x: False
;也就是说不忽略任何值。 例如,传入:
lambda x: x in " \t"
如果你以字符序列的形式对行进行比较,并且不希望区分空格符或硬制表符。
可选参数 a 和 b 为要比较的序列;两者默认为空字符串。 两个序列的元素都必须为 hashable。
可选参数 autojunk 可用于启用自动垃圾启发式计算。
SequenceMatcher
对象拥有以下方法
1.设置序列有三个函数
set_seqs
(a, b):同时设置两个序列
set_seq1
(a):只设置第一个序列
set_seq2
(a):只设置第二个序列
2.find_longest_match
(alo=0, ahi=None, blo=0, bhi=None)
功能:找出 a[alo:ahi]
和 b[blo:bhi]
中的最长匹配块
返回值: named tuple Match(a, b, size)
。(我并不懂具名元组是个啥,反正是元组类型,这个match可能有某些含义)
如果未找到匹配块,此方法将返回 (alo, blo, 0)
a.如果 isjunk 被省略或为 None (ps:不忽略空格)
find_longest_match()
将返回 (i, j, k)
使得 a[i:i+k]
等于 b[j:j+k]
,其中 alo <= i <= i+k <= ahi
并且 blo <= j <= j+k <= bhi
。 对于所有满足这些条件的 (i', j', k')
,如果 i == i'
, j <= j'
也被满足,则附加条件 k >= k'
, i <= i'
。 换句话说,对于所有最长匹配块,返回在 a 当中最先出现的一个,而对于在 a 当中最先出现的所有最长匹配块,则返回在 b 当中最先出现的一个。
简言之:返回第一个最长的匹配位置,i为a中起点下标,j为b中起点下标,k为匹配块的长度
s = SequenceMatcher(None, " abcd", "abcd abcd")
s.find_longest_match(0, 5, 0, 9)
#输出Match(a=0,b=4,size=5)
输出确实长这样。。。
取值可以使用m=返回值,m.a取出0,m.b=5,m.size=1
b.如果提供了 isjunk (ps:忽略空格)
将按上述规则确定第一个最长匹配块,但额外附加不允许块内出现垃圾元素的限制。 然后将通过(仅)匹配两边的垃圾元素来尽可能地扩展该块。 这样结果块绝对不会匹配垃圾元素,除非同样的垃圾元素正好与有意义的匹配相邻。
这是与之前相同的例子,但是将空格符视为垃圾。 这将防止 ' abcd'
直接与第二个序列末尾的 ' abcd'
相匹配。 而只可以匹配 'abcd'
,并且是匹配第二个序列最左边的 'abcd'
:
s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
s.find_longest_match(0, 5, 0, 9)
#输出 Match(a=1, b=0, size=4)
3.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)]
4. ratio
()
功能和返回值:返回一个取值范围 [0, 1] 的浮点数作为序列相似性度量。
其中 T 是两个序列中元素的总数量,M 是匹配的数量,即 2.0*M / T。 请注意如果两个序列完全相同则该值为 1.0
,如果两者完全不同则为 0.0
。
实测如下,分母T应该是未去重的两个字符串长度之和,分子M是重合的字符串长度,以下四个结果都符合这个推断:
如果 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
quick_ratio
()
相对快速地返回一个 ratio()
的上界。
real_quick_ratio
()
非常快速地返回一个 ratio()
的上界。
这三个返回匹配部分占字符总数的比率的方法可能由于不同的近似级别而给出不一样的结果,但是 quick_ratio()
和 real_quick_ratio()
总是会至少与 ratio()
一样大:
s = SequenceMatcher(None, "abcd", "bcde")
s.ratio()
#0.75
s.quick_ratio()
#0.75
s.real_quick_ratio()
#1.0
实操
from difflib import SequenceMatcher
代码:在find_longest_match的时候,本来传len()-1却有问题,应该直接传len
输出:
由于第五行传入的是两个字符串的公共串,所以ratio一定为1
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)