difflib

此模块提供了用于比较序列的类和函数。它可以用于例如比较文件,并且可以产生各种格式的差异信息,包括HTML和上下文以及统一差异。

difflib 模块包含用于计算和处理序列间差异的工具。它特别适用于比较文本,包括使用几种常见差异格式生成报告的函数。

本节中的示例将在扩散数据中使用这个常见的测试difflib_data.py模块:

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

Comparing Bodies of Text

class difflib.Differ:这是一个类,用于比较文本行的序列,并产生人类可读的差异或增量。Differ使用SequenceMatcher来比较行的序列,并比较类似(接近匹配)行内的字符序列。

Differ delta的每一行都以两个字母的代码开头:

  • ' - ' 序列1独有
  • '+ ' 序列2独有
  • ' ' 两个序列共有的
  • '? ' 行不存在于任一输入序列中

class difflib.Differ(linejunk=None, charjunk=None):

可选的关键字参数linejunk和charjunk用于过滤器功能(或None):

  • linejunk:接受单个字符串参数的函数,如果字符串是junk,则返回true。默认值为None,表示没有行被认为是垃圾。
  • charjunk:接受单个字符参数(长度为1的字符串)的函数,如果字符是垃圾则返回true。默认值为None,表示没有字符被认为是垃圾。

这些垃圾过滤功能加速匹配以发现差异,并且不会导致任何不同的行或字符被忽略。

通过单个方法使用Differ对象(生成增量):

  • compare(a, b):比较两个序列的行,并生成增量(行序列)。

每个序列必须包含以换行符结尾的单个单行字符串。这样的序列可以从文件状对象的readlines()方法获得。生成的增量还包括以换行符结束的字符串,可以通过类似于文件的对象的writelines()方法按原样打印。

举例

Differ 的类在文本行序列上工作,并产生人类可读的增量,或者改变指令,包括不同的行内的差异。Differ 的默认输出类似于Unix下的diff命令行工具。它包括来自两个列表的原始输入值,包括通用的值,以及标记数据,以指示进行了哪些更改。

  • 在第一个序列中,-是在第一个序列中,而不是第二个序列。
  • 以+为前缀的行是在第二个序列中,但不是第一个序列。
  • 如果一条线在不同的版本之间有一个增量的差异,那么一个额外的线会被固定 ?用于在新版本中突出显示更改。
  • 如果一行没有更改,那么在左边的列上将会有一个额外的空白空间,以便它与其他可能有差异的输出对齐。

将文本分解为一个单独的行序列,然后将其传递给compare()会产生比在大字符串中传递更容易读的输出。

import difflib
from difflib_data import * d = difflib.Differ()
diff = d.compare(text1_lines, text2_lines)
print('\n'.join(diff))

示例数据中的两个文本段的开头都是相同的,所以第一行没有任何额外的注释。

  Lorem ipsum dolor sit amet, consectetuer adipiscing
elit. Integer eu lacus accumsan arcu fermentum euismod. Donec

数据的第三行已经更改为在修改后的文本中包含一个逗号。这一行的两个版本都被打印出来了,第5行中额外的信息显示了文本被修改的列,其中包括添加了字符的事实。

- pulvinar porttitor tellus. Aliquam venenatis. Donec facilisis
+ pulvinar, porttitor tellus. Aliquam venenatis. Donec facilisis
? +

接下来的几行输出显示额外的空间被删除了。

- pharetra tortor.  In nec mauris eget magna consequat
? - + pharetra tortor. In nec mauris eget magna consequat

接下来,一个更复杂的变化出现了,用一个短语代替了几个单词。

- convalis. Nam sed sem vitae odio pellentesque interdum. Sed
? - -- + 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. Suspendisse eu lectus. In nunc. Duis vulputate
- tristique enim. Donec quis lectus a justo imperdiet tempus.
+ adipiscing. Duis vulputate tristique enim. Donec quis lectus a
+ justo imperdiet tempus. Suspendisse eu lectus. In nunc.

Other Output Formats

difflib.unified_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'):比较a和b(字符串列表);以统一差分格式返回增量(generator生成增量线)。

统一差异是一种紧凑的方式,仅显示已更改的行,以及几行上下文。更改以内联样式显示(而不是单独的前/后块)。上下文线的数量由n设置,默认为三个。

默认情况下,使用尾随换行创建diff控制行(具有---,+++或@@的那些)这有助于使从io.IOBase.readlines()创建的输入产生适合与io.IOBase.writelines()一起使用的差异,因为输入和输出具有尾随换行符。

对于没有尾随换行符的输入,将lineterm参数设置为"",以便输出将一律换行。

上下文差异格式通常具有文件名和修改时间的头。可以使用fromfile,tofile,fromfiledate和tofiledate的字符串指定这些中的任何一个或全部。修改时间通常以ISO 8601格式表示。如果未指定,则字符串默认为空。

举例

尽管Differ 的类显示了所有的输入行,但是一个统一的diff只包含了修改的行和一些上下文。unified_diff()函数产生这种类型的输出。

import difflib
from difflib_data import * diff = difflib.unified_diff(
text1_lines,
text2_lines,
lineterm='',
)
print('\n'.join(list(diff)))

lineterm参数用于告诉unified_diff()跳过新行到它返回的控制行,因为输入行不包括它们。当打印出来的时候,所有的行都添加了换行符。对于许多流行的版本控制工具的用户来说,输出应该是很熟悉的。

---
+++
@@ -1,11 +1,11 @@
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
+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. Suspendisse eu lectus. In nunc. Duis vulputate
-tristique enim. Donec quis lectus a justo imperdiet tempus.
+adipiscing. Duis vulputate tristique enim. Donec quis lectus a
+justo imperdiet tempus. Suspendisse eu lectus. In nunc.

Junk Data

class difflib.SequenceMatcher(isjunk=None, a='', b='', autojunk=True):可选参数isjunk必须是None(默认值)或单参数函数,它接受一个序列元素,并且当且仅当元素是“junk”被忽略。将None传递给isjunk等效于传递lambda x: 0 ;换句话说,没有元素被忽略。例如,pass。

如果你将行作为字符序列进行比较,并且不想在空白或硬标签上同步。

可选参数a和b是要比较的序列;两者默认为空字符串。这两个序列的元素必须hashable。

可选参数autojunk可用于禁用自动垃圾启发式。

SequenceMatcher对象具有以下方法:

  • set_seqs(a, b):设置要比较的两个序列。

    SequenceMatcher计算和缓存有关第二个序列的详细信息,因此如果要比较一个序列与许多序列,请使用set_seq2()设置常用序列一次,并调用set_seq1(),对每个其他序列重复一次。
  • set_seq1(a):设置要比较的第一个序列。要比较的第二个序列不更改。
  • set_seq2(b):设置要比较的第二个序列。第一个要比较的序列不会改变。
  • find_longest_match(alo, ahi, blo, bhi):在a[alo:ahi]和b[blo:bhi]中查找最长匹配块。

    If isjunk was omitted or None, find_longest_match() returns (i, j, k) such that a[i:i+k] is equal to b[j:j+k], where alo <= i <= i+k <= ahi and blo <= j <= j+k <= bhi. 对于满足那些条件的所有(i', j', k'),附加条件k = k',i / t10> i',并且如果i == t12>,j j'。换句话说,在所有最大匹配块中,返回在a中最早开始的块,并且在a中开始最早的所有最大匹配块返回一个开始最早在b。
  • get_matching_blocks():描述匹配子序列的三元组的返回列表。每个三元组具有形式(i, j, n),并且意味着 a [i:i + n] == b [j:j + n]。三元组在i和j中单调递增。

    最后三个是虚拟的,并且具有值(len(a), len(b), 0) t0>。它是n == 0的唯一三元组。如果(i, j, n)和> j', n')是列表中的相邻三元组,第二个不是列表中的最后一个三元组,则 != i'或j + n / t14> j';换句话说,相邻三元组总是描述不相邻的相等块。
  • get_opcodes():描述如何将a转换为b的5元组返回列表。每个元组具有(标签, i1, i2, j1, j2 )。第一个元组有i1 = = j1 = = 0,还有i1等于从前面的元组,和,同样,等于以前的j2 j1 i2剩余的元组。
  • get_grouped_opcodes(n=3):返回具有高达n行上下文的组的generator。

http://usyiyi.cn/translate/python_352/library/difflib.html

举例

所有产生差异序列的函数都接受参数,以指示应该忽略哪些行,以及应该忽略行中的哪些字符。例如,这些参数可用于跳过文件的两个版本中的标记或空格更改。

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() 的默认值是忽略空格和制表符。

A = ' abcd'
B = 'abcd abcd' Without junk detection:
a = 0
b = 4
size = 5
A[a:a+size] = ' abcd'
B[b:b+size] = ' abcd' Treat spaces as junk:
a = 1
b = 0
size = 4
A[a:a+size] = 'abcd'
B[b:b+size] = 'abcd'

Comparing Arbitrary Types

举例

SequenceMatcher类可以比较任何类型的两个序列,只要该值是可哈希的。 它使用一种算法来识别序列中最长的连续匹配块,消除对实际数据无贡献的“junk”值。

函数get_opcodes()返回修改第一个序列以使其与第二个序列匹配的指令列表。 指令被编码为五元组元组,包括字符串指令(“opcode”,见下表)以及序列中的两对起始和停止索引(表示为i1,i2,j1和j2)。

Opcode Definition
'replace' Replace a[i1:i2] with b[j1:j2]
'delete' Remove a[i1:i2] entirely
'insert' Insert b[j1:j2] at a[i1:i1]
'equal' The subsequences are already equal
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)

本例比较两个整数列表,并使用getopcode()来获得将原始列表转换为新版本的指令。这些修改被应用于相反的顺序,这样在添加和删除条目之后,列表索引仍然是正确的。

Initial data:
s1 = [1, 2, 3, 5, 6, 4]
s2 = [2, 3, 5, 4, 6, 1]
s1 == s2: False Replace [4] from s1[5:6]with [1] from s2[5:6]
before = [1, 2, 3, 5, 6, 4]
after = [1, 2, 3, 5, 6, 1] s1[4:5] and s2[4:5] are the same
after = [1, 2, 3, 5, 6, 1] Insert [4] from s2[3:4] into s1 at 4
before = [1, 2, 3, 5, 6, 1]
after = [1, 2, 3, 5, 4, 6, 1] s1[1:4] and s2[0:3] are the same
after = [1, 2, 3, 5, 4, 6, 1] Remove [1] from positions [ 0: 1]
before = [1, 2, 3, 5, 4, 6, 1]
after = [2, 3, 5, 4, 6, 1] s1 == s2: True

python difflib.md的更多相关文章

  1. python difflib详解

    difflib -帮助进行差异化比较 这个模块提供的类和方法用来进行差异化比较,它能够生成文本或者html格式的差异化比较结果,如果需要比较目录的不同,可以使用filecmp模块. class dif ...

  2. python 实现 md文档自动编号

    目录 1. 原理 2. 运行方法 3. 效果 4. 代码 1. 原理 正则匹配对相应字符串进行替换 2. 运行方法 python md_convert.py [a.md, b.md,...] # 转换 ...

  3. Python sys.md

    sys-System-specific Configuration Interpreter Settings sys包含用于访问解释器的编译时或运行时配置设置的属性和函数. Build-time Ve ...

  4. Python os.md

    os 便携式访问操作系统的特定功能.os模块提供了对特定平台模块(如posix, nt, mac)的封装, 函数提供的api在很多平台上都可以相同使用, 所以使用os模块会变得很方便. 但不是所有函数 ...

  5. python string.md

    string 包含用于处理文本的常量和类.string模块始于Python的最早版本. 2.0版本中, 许多之前只在模块中实现的函数被转移为string对象的方法. 之后的版本中, 虽然这些函数仍然可 ...

  6. Python glob.md

    glob 即使glob API非常简单, 但这个模块包含了很多的功能. 在很多情况下, 尤其是你的程序需要寻找出文件系统中, 文件名匹配特定模式的文件时, 是非常有用的. 如果你需要包含一个特定扩展名 ...

  7. python textwrap.md

    textwrap textwrap模块可以用来格式化文本, 使其在某些场合输出更美观. 他提供了一些类似于在很多文本编辑器中都有的段落包装或填充特性的程序功能. Example Data 本节中的示例 ...

  8. Python shutil.md

    shutil shutil模块包括高级文件操作,例如复制和归档. Copying Files shutil.copyfileobj(fsrc, fdst[, length]):将类似文件的对象fsrc ...

  9. Python csv.md

    csv csv模块可以用于处理从电子表格和数据库导出的数据到带有字段和记录格式的文本文件,通常称为逗号分隔值(csv)格式,因为逗号通常用于分隔记录中的字段. Reading csv.reader(c ...

随机推荐

  1. SQL Server T—SQL 函数

    一 聚合函数(统计函数)!!!!! 计算个数   count(  )   select count(*) from 表名 求和  sum(  ) select sum(列名) from 表名 求平均数 ...

  2. js实现iview表格 排名列

    (有误,请勿观看) 一.排名的简单实现 //排名例子1 //需要排名的数组 //var myArray = [5,7, 7, 9, 8, 6, 23]; //新数组 //var thisArray = ...

  3. Web前端基础——CSS

    一.CSS概述 css ( cascading style sheets ) 层叠样式表,可以轻松设置网页元素的显示.位置和格式外,甚至还能产生滤镜,图像 淡化,网页淡入淡出的渐变效果,简而言之,cs ...

  4. Java基础——iO(三)

    一.管道流 演示:PipedInputStream  , PipedOutputStream 注意:管道流本身就不建议在一个线程中使用,这是因为向输出流中写的数据,都会存到输入流内部的一个1024字节 ...

  5. 随机错乱排序(sort的应用)

    新手上路,大家多多指教哈,,, #include <iostream> #include <algorithm> #include <ctime> using na ...

  6. 如何调试JDK源代码并查看局部变量值

    如下图: 按F5进入String.startsWith,如下: 点“Edit Source Lookup Path” 附加源代码,如下图: 附加上源代码后如下: 可以看到,当鼠标放在“prefix”上 ...

  7. EF数据库优先模式(二)

    接着上一节的内容,建立好EF数据模型(DataFirst)之后,创建一个借口类,将公用的借口放到接口类里面 public interface IObjectLoader<T,TM> {  ...

  8. Linux常用基本命令[find]用法(1)

    find是个很强大的命令,用法很多. 作用:查找目录下的文件,同时也可以调用其他命令执行相应的操作 用法: find [选项] [路径][操作语句] find [-H] [-L] [-P] [-D d ...

  9. Django中连接redis

    1. 安装 pip install django-redis 2. settings中配置 CACHES = { "default": { "BACKEND": ...

  10. java中System.currentTimeMillis()

    System.curentTimeMillis();会产生一个当前的毫秒. 1.计算某个方法的耗时 long curTime = System.currentTimeMillis(); resourc ...