Python文本处理(二)difflib & textwrap 模块

difflib模块提供文本比较类和函数,如SequenceMatcher、Differ、HtmlDiff,用于计算文本差异并生成不同格式的差异信息。SequenceMatcher通过灵活的算法比较序列,支持自动丢弃垃圾字符串。Differ类则生成人类可读的差异,而HtmlDiff生成HTML格式的差异。textwrap模块则提供wrap、fill、dedent等功能,用于文本的环绕和填充,方便处理文本格式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

difflib模块用来辅助计算文本差异,difflib模块提供比较序列的类和函数,可以用来进行序列或文件的比较并产生不同格式的信息,包括HTML和上下文以及统一格式的差异。

difflib文本比较类

​ difflib提供了用来文本比较的类,有以下内容

SequenceMatcher

​  SequenceMatcher:序列分析器,可以用于比较任何序列元素是可哈希的序列对,该类比较灵活。所采用的基本算法是在20世纪80年代后期由Ratcliff和Obsershelp提出来的,该基本算法的另一种叫法是”格式塔模式匹配算法”,算法的思想是找到最长的连续匹配子序列,子序列不包含无意义的空行或空字符,之后将该思想应用到递归匹配序列左侧和右侧序列片段。

时间控制&自动标识丢弃垃圾字符串

​ 在时间复杂度上,SequenceMatcher用来做比较时的最坏算法时间复杂度是$O(n^2)$, 最佳情况的时间复杂度是线性的$O(n)$,其预期情况取决于由多少个元素以及元素之间的复杂程度。

​  垃圾自动标识和触发丢弃功能也是SequenceMatcher的另一项重要功能。SequenceMatcher支持自动将某些序列视为垃圾并自动丢弃。垃圾自动标识是计算每个项目在序列中出现的次数,如果一个项目的重复项占序列的1%以上,并且序列长度至少为200个项目,则该项目会被标记为”受欢迎”被视为垃圾自动丢弃,以便更好的进行序列匹配。在创建SequenceMatcher的时候,可以通过将autojunk参数设置为false的方式关闭此功能。不过autojunk参数是Python3.2才有的功能。

SequenceMatcher构建

​  SequenceMatcher的创建函数用模块级别函数difflib.SequenceMatcher(isjunk=Nonea=’’b=’’autojunk=True),可选参数isjunk必须是none(默认值),或者是一个单参数函数,该函数接受一个序列元素,并且仅当该元素被定义为垃圾字符且应被忽略时才返回true。为isjunk传递none等同于传递lambda x:0;换句话说,不忽略任何元素。如以下lambda函数

lambda x:x in '\t'

以上代表如果将行作为字符序列进行比较,并且在空白或硬制表符上不进行同步比较。

​ 可选参数ab是要比较的序列;都默认为空字符串。两个序列的元素都必须是可哈希的;可选参数autojunk可用于禁用自动垃圾启发式。

​  SequenceMatcher对象有三个数据属性:当isjunk值为true时,bjunk是b的一组元素;bpoular是垃圾自动启发式控制,如果bpoular没有被禁用,则认为出现频率高的字符并非垃圾元素;b2j是将b的其余元素映射到它们出现的位置列表的dict。当通过set_seqs()set_seq2()重置字符列表b时,这三个参数都会跟着重置。

SequenceMatcher函数

​  SequenceMatcher对象有以下操作函数:

set_seqs()

​  set_seqs(a,b)比较两个字符序列。SequenceMatcher计算并缓存有关第二个序列的详细信息,因此,如果要将一个序列与多个序列进行比较,请使用set_seq2()将常用的序列设置一次,并对其他每个序列重复调用set_seq1()

set_seq1()

​  set_seq1(a) 设置要比较的第一个序列,要比较的第二个序列不发生改变。

set_seq2()

​  set_seq2(b)设置要比较的第二个序列,要比较的第一个序列不发生改变。

find_longest_match()

​  find_longest_match(alo, ahi, blo, bhi)在a[alo:ahi]b[blo:bhi]中查找最长的匹配块,并返回一个被命名的元组Match(a, b, size)

​ 如果isjunk被省略或没有,则find longer_match()返回(i,j,k),使a[i:i+k]等于b[j:j+k],其中alo<=i<=i+k<=ahiblo<=j<=j+k<=bhi。对于满足这些条件的所有(i’,j’,k’)而言,如果满足i==i’`,j<=j’,则满足附加条件k>=k’i<=i’。换句话说,在所有最大匹配块中,返回在a中最早开始的匹配块,在a中最早开始的最大匹配块中,返回在`b中最早开始的匹配块。

>>> import difflib
>>> s = difflib.SequenceMatcher(None, 'abcd', 'abcd abcd')
>>> s.find_longest_match(0,4,0,9)
Match(a=0, b=0, size=4)
>>> 

如果提供了isjunk,则首先按照上述方法确定最长的匹配块,但有一个附加限制,即块中不显示任何垃圾元素。然后,通过匹配(仅)两侧的垃圾元素,尽可能扩展该块。因此,结果块永远不会在垃圾上匹配,除非相同的垃圾恰好与一个有趣的匹配相邻。

>>> s = difflib.SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
>>> s.find_longest_match(0, 5, 0, 9)
Match(a=1, b=0, size=4)

这个举例与上一个举例一样,但是考虑到空白是垃圾。设置isjunk后将阻止“abcd”直接匹配第二个序列末尾的“abcd”。相反,只有“abcd”可以匹配,并且在第二个序列中与最左边的“abcd”匹配,如果没有匹配块,将返回(alo, blo, 0)

get_matching_blocks()

​  get_matchinig_blocks()返回描述非重叠匹配子序列的三元组列表。每个三元组的形式是(i,j,n),意思是a[i:i+n]==b[j:j+n]ij在三元组中是单调递增的。最后一个三元组是一个虚拟值,数值为(len(a)、len(b)、0),是唯一一个n==0的三元组。如果(i,j,n)和(i’,j’,n’)是列表中的相邻三元,而第二个不是列表中的最后一个三元,则i+n<i’或j+n<j’;换句话说,相邻三元总是描述非相邻的相等块。

>>> s = difflib.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()

​  get_opcodes()返回描述如何将a转换为b的5个元组的列表。每个元组的形式为(tag,i1,i2,j1,j2)。第一个元组的i1==j1==0,其余的元组的i1等于前一个元组的i2,同样,j1等于前一个j2

tag参数是string形式,其值与含义如下:

含义
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值