码迷,mamicode.com
首页 > 编程语言 > 详细

python difflib.md

时间:2017-07-28 19:24:22      阅读:372      评论:0      收藏:0      [点我收藏+]

标签:nec   python   信息   命令   关键字   微软   字母   三元   创建   

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

标签:nec   python   信息   命令   关键字   微软   字母   三元   创建   

原文地址:http://www.cnblogs.com/cuchadanfan/p/7251813.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!