difflib
— 增量计算帮手
¶
源代码: Lib/difflib.py
此模块提供用于比较序列的类和函数。例如,用于比较文件,并产生各种格式的差异信息,包括 HTML、上下文及统一 diff。为比较目录和文件,另请参阅
filecmp
模块。
difflib.
SequenceMatcher
¶
这是用于比较任何类型序列对的灵活类,只要序列元素 hashable . The basic algorithm predates, and is a little fancier than, an algorithm published in the late 1980’s by Ratcliff and Obershelp under the hyperbolic name “gestalt pattern matching.” The idea is to find the longest contiguous matching subsequence that contains no “junk” elements; these “junk” elements are ones that are uninteresting in some sense, such as blank lines or whitespace. (Handling junk is an extension to the Ratcliff and Obershelp algorithm.) The same idea is then applied recursively to the pieces of the sequences to the left and to the right of the matching subsequence. This does not yield minimal edit sequences, but does tend to yield matches that “look right” to people.
计时:
基本 Ratcliff-Obershelp 算法在最坏情况下是时间的 3 次方,且在预期情况下是时间的 2 次方。
SequenceMatcher
对于最坏情况是时间的 2 次方,且预期情况行为从属序列共有多少元素的复杂方式;最佳情况是线性时间。
自动 junk 试探:
SequenceMatcher
支持自动将某些序列项视为 junk 的试探。试探计数各单项在序列中出现多少次。若项重复 (在第一项后) 得分占序列 1% 以上且序列至少 200 项,则此项被标记为 popular (流行),且出于序列匹配目的将被视为 junk。可以关闭这种试探通过设置
autojunk
自变量为
False
当创建
SequenceMatcher
.
3.2 版新增: autojunk 参数。
difflib.
Differ
¶
这是用于比较文本行序列,并产生人类可读的差异或增量的类。Differ 使用
SequenceMatcher
来比较行序列,及比较相似 (接近匹配) 行中的字符序列。
各行的
Differ
增量以 2 字母代码开始:
| Code | 含义 |
|---|---|
'-
'
|
序列 1 的唯一行 |
'+
'
|
序列 2 的唯一行 |
'
'
|
2 序列的共有行 |
'?
'
|
在任一输入序列中都不存在行 |
行开始采用
?
试图引导眼睛看向行内差异,且未呈现在任一输入序列中。这些行可能造成混淆,若序列包含 Tab (制表符)。
difflib.
HtmlDiff
¶
此类可用于创建并排展示的 HTML 表格 (或包含表格的完整 HTML 文件),逐行比较具有行间和行内改变突显的文本。可以按完整 (或上下文) 差异模式生成表格。
此类的构造函数:
__init__
(
tabsize=8
,
wrapcolumn=None
,
linejunk=None
,
charjunk=IS_CHARACTER_JUNK
)
¶
初始化实例
HtmlDiff
.
tabsize
是可选关键词自变量,用于指定 Tab 间距且默认为
8
.
wrapcolumn
是可选关键词,用于指定要断行和换行的列号,默认为
None
行不换行。
linejunk
and
charjunk
是可选关键词自变量被传入
ndiff()
(用于
HtmlDiff
以生成并排 HTML 差异)。见
ndiff()
文档编制了解自变量默认值和描述。
以下是公开方法:
make_file
(
fromlines
,
tolines
,
fromdesc=''
,
todesc=''
,
context=False
,
numlines=5
,
*
,
charset='utf-8'
)
¶
比较 fromlines and tolines (字符串列表) 并返回完整 HTML 文件字符串 (包含具有行间和行内改变突显,逐行展示差异的表格)。
fromdesc and todesc 是可选关键词自变量,用于指定从/到文件列标题字符串 (两者默认为空字符串)。
context
and
numlines
两者是可选关键词自变量。设置
context
to
True
当要展示上下文差异时,否则默认为
False
以展示完整文件。
numlines
默认为
5
。当
context
is
True
numlines
控制围绕差异突显的上下文行数。当
context
is
False
numlines
控制差异突显之前展示的行数,当使用下一超链接时 (设置为 0 导致下一超链接,将下一差异突显放置在浏览器顶部,没有任何前导上下文)。
3.5 版改变:
charset
仅关键词自变量被添加。改变 HTML 文档默认字符集从
'ISO-8859-1'
to
'utf-8'
.
make_table
(
fromlines
,
tolines
,
fromdesc=''
,
todesc=''
,
context=False
,
numlines=5
)
¶
比较 fromlines and tolines (字符串列表) 并返回完整 HTML 表格字符串 (具有行间和行内改变突显,逐行展示差异)。
此方法自变量如同那些自变量对于
make_file()
方法。
Tools/scripts/diff.py
是此类的命令行前端,且包含其用法的很好范例。
difflib.
context_diff
(
a
,
b
,
fromfile=''
,
tofile=''
,
fromfiledate=''
,
tofiledate=''
,
n=3
,
lineterm='\n'
)
¶
比较 a and b (字符串列表);返回增量 ( generator 生成增量行) 按上下文 diff 格式。
上下文 diff 是仅仅展示有改变行及几行上下文的紧凑方式。改变按之前/之后样式展示。上下文行数的设置通过 n 默认为 3。
默认情况下,diff 控制行 (带有
***
or
---
) 的创建采用结尾换行符。这很有帮助,以便创建输入从
io.IOBase.readlines()
结果在 diff,适合用于
io.IOBase.writelines()
由于输入/输出两者拥有结尾换行符。
对于没有结尾换行符的输入,设置
lineterm
自变量为
""
以便输出会自由地一致换行。
上下文 diff 格式通常拥有用于文件名和修改时间的 Header 头。可以指定所有这些中的任一,通过使用字符串为 fromfile , tofile , fromfiledate ,和 tofiledate 。修改时间通常以 ISO 8601 格式表示。若不指定,字符串默认为空。
>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']
>>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']
>>> sys.stdout.writelines(context_diff(s1, s2, fromfile='before.py', tofile='after.py'))
*** before.py
--- after.py
***************
*** 1,4 ****
! bacon
! eggs
! ham
guido
--- 1,4 ----
! python
! eggy
! hamster
guido
见 difflib 命令行接口 了解更详细范例。
difflib.
get_close_matches
(
word
,
possibilities
,
n=3
,
cutoff=0.6
)
¶
返回足够好的最佳匹配列表。 word 是期望接近匹配的序列 (通常是字符串),和 possibilities 是序列列表针对要匹配 word (通常是字符串列表)。
可选自变量
n
(默认
3
) 是要返回的接近匹配最大数;
n
必须大于
0
.
可选自变量
cutoff
(默认
0.6
) 是 [0,1] 范围内的浮点数。不得分的可能性至少类似
word
被忽略。
最佳 (不超过 n ) 以列表形式返回可能性匹配,按相似性得分排序,最相似第一。
>>> get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'])
['apple', 'ape']
>>> import keyword
>>> get_close_matches('wheel', keyword.kwlist)
['while']
>>> get_close_matches('pineapple', keyword.kwlist)
[]
>>> get_close_matches('accept', keyword.kwlist)
['except']
difflib.
ndiff
(
a
,
b
,
linejunk=None
,
charjunk=IS_CHARACTER_JUNK
)
¶
比较
a
and
b
(字符串列表);返回
Differ
样式增量 (
generator
生成增量行)。
可选关键词参数
linejunk
and
charjunk
是过滤函数 (或
None
):
linejunk
:函数接受单字符串自变量并返回 True 若字符串是 junk,或 False 若字符串不是 junk。默认为
None
。还存在模块级函数
IS_LINE_JUNK()
,过滤掉没有可见字符的行,除最多一镑字符外 (
'#'
) – 不管怎样,底层
SequenceMatcher
类会动态分析哪些行如此频繁以至构成噪声,且这通常比使用此函数工作得更好。
charjunk
:函数接受字符 (1 长字符串) 并返回 True 若字符是 junk,或 False 若字符不是 junk。默认为模块级函数
IS_CHARACTER_JUNK()
,过滤掉空白字符 (Blank 或 Tab;在其中包括换行符是坏主意)。
Tools/scripts/ndiff.py
是此函数的命令行前端。
>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True),
... 'ore\ntree\nemu\n'.splitlines(keepends=True))
>>> print(''.join(diff), end="")
- one
? ^
+ ore
? ^
- two
- three
? -
+ tree
+ emu
difflib.
restore
(
sequence
,
which
)
¶
返回生成增量的 2 序列之一。
给定
sequence
的产生通过
Differ.compare()
or
ndiff()
,提取行源自文件 1 或 2 (参数
which
),剥离掉行前缀。
范例:
>>> diff = ndiff('one\ntwo\nthree\n'.splitlines(keepends=True),
... 'ore\ntree\nemu\n'.splitlines(keepends=True))
>>> diff = list(diff) # materialize the generated delta into a list
>>> print(''.join(restore(diff, 1)), end="")
one
two
three
>>> print(''.join(restore(diff, 2)), end="")
ore
tree
emu
difflib.
unified_diff
(
a
,
b
,
fromfile=''
,
tofile=''
,
fromfiledate=''
,
tofiledate=''
,
n=3
,
lineterm='\n'
)
¶
比较 a and b (字符串列表);返回增量 ( generator 生成增量行) 按统一 diff 格式。
统一 diff 是仅仅展示有改变行及几行上下文的紧凑方式。以内联样式展示改变 (而不是单独的之前/之后块)。设置上下文行数通过 n 默认为 3。
默认情况下,diff 控制行 (带有
---
,
+++
,或
@@
) 的创建采用结尾换行符。这很有帮助,以便创建输入从
io.IOBase.readlines()
结果在 diff,适合用于
io.IOBase.writelines()
由于输入/输出两者拥有结尾换行符。
对于没有结尾换行符的输入,设置
lineterm
自变量为
""
以便输出会自由地一致换行。
上下文 diff 格式通常拥有用于文件名和修改时间的 Header 头。可以指定所有这些中的任一,通过使用字符串为 fromfile , tofile , fromfiledate ,和 tofiledate 。修改时间通常以 ISO 8601 格式表示。若不指定,字符串默认为空。
>>> s1 = ['bacon\n', 'eggs\n', 'ham\n', 'guido\n']
>>> s2 = ['python\n', 'eggy\n', 'hamster\n', 'guido\n']
>>> sys.stdout.writelines(unified_diff(s1, s2, fromfile='before.py', tofile='after.py'))
--- before.py
+++ after.py
@@ -1,4 +1,4 @@
-bacon
-eggs
-ham
+python
+eggy
+hamster
guido
见 difflib 命令行接口 了解更详细范例。
difflib.
diff_bytes
(
dfunc
,
a
,
b
,
fromfile=b''
,
tofile=b''
,
fromfiledate=b''
,
tofiledate=b''
,
n=3
,
lineterm=b'\n'
)
¶
比较
a
and
b
(bytes 对象列表) 使用
dfunc
;产生增量行 (还是 bytes) 序列按格式返回通过
dfunc
.
dfunc
必须是可调用,通常为
unified_diff()
or
context_diff()
.
允许比较具有未知或不一致编码的数据。所有输入除了
n
必须是 bytes 对象,非 str。工作通过无损转换所有输入 (除了
n
) 到 str,和调用
dfunc(a,
b,
fromfile,
tofile,
fromfiledate,
tofiledate,
n,
lineterm)
。输出的
dfunc
然后转换回 bytes,因此收到的增量行拥有相同的未知/不一致编码如
a
and
b
.
3.5 版新增。
difflib.
IS_LINE_JUNK
(
line
)
¶
返回 True 对于可忽略行。行
line
可忽略若
line
为 Blank 或包含单
'#'
,否则不可忽略。用作默认参数
linejunk
in
ndiff()
在旧版本中。
difflib.
IS_CHARACTER_JUNK
(
ch
)
¶
返回 True 对于可忽略字符。字符
ch
可忽略若
ch
为 Space 或 Tab,否则不可忽略。用作默认参数
charjunk
in
ndiff()
.
另请参阅
SequenceMatcher
类拥有此构造函数:
difflib.
SequenceMatcher
(
isjunk=None
,
a=''
,
b=''
,
autojunk=True
)
可选自变量
isjunk
必须是
None
(默认) 或接受序列元素和仅当元素是 junk 且应该被忽略才返回 True 的一自变量函数。传递
None
for
isjunk
相当于传递
lambda
x:
0
;换句话说,元素不被忽略。例如,传递:
lambda x: x in " \t"
若将行作为字符序列进行比较,且不想在 Blank 或硬 Tab 上同步。
可选自变量 a and b 是要比较的序列;两者默认为空字符串。2 序列的元素必须 hashable .
可选自变量 autojunk 可以用于禁用自动 junk 试探。
3.2 版新增: autojunk 参数。
SequenceMatcher 对象获得 3 数据属性:
bjunk
是元素集对于
b
其中
isjunk
is
True
;
bpopular
是试探 (若未禁用) 认为流行的非 junk 元素集;
b2j
是字典映射剩余元素对于
b
到它们发生位置的列表。重置所有 3 者每当
b
被重置采用
set_seqs()
or
set_seq2()
.
3.2 版新增: bjunk and bpopular 属性。
SequenceMatcher
对象拥有下列方法:
set_seqs
(
a
,
b
)
¶
设置 2 要比较序列。
SequenceMatcher
计算并缓存有关第 2 序列的详细信息,因此,若想要比较一个序列同多个序列,使用
set_seq2()
以设置常用序列一次和调用
set_seq1()
重复,其它序列每个一次。
set_seq1
(
a
)
¶
设置要比较的第 1 序列。要比较的第 2 序列不变。
set_seq2
(
b
)
¶
设置要比较的第 2 序列。要比较的第 1 序列不变。
find_longest_match
(
alo
,
ahi
,
blo
,
bhi
)
¶
查找最长匹配块在
a[alo:ahi]
and
b[blo:bhi]
.
若
isjunk
被省略或
None
,
find_longest_match()
返回
(i,
j,
k)
这样
a[i:i+k]
等于
b[j:j+k]
,其中
alo
<=
i
<=
i+k
<=
ahi
and
blo
<=
j
<=
j+k
<=
bhi
。对于所有
(i',
j',
k')
满足这些条件,额外条件
k
>=
k'
,
i
<=
i'
,且若
i
==
i'
,
j
<=
j'
也满足。换句话说,所有最大匹配块,返回一个最早开始在
a
,及所有这些最大匹配块的最早开始在
a
,返回一个最早开始在
b
.
>>> s = SequenceMatcher(None, " abcd", "abcd abcd")
>>> s.find_longest_match(0, 5, 0, 9)
Match(a=0, b=4, size=5)
若 isjunk 被提供,第 1 最长匹配块的确定如上文,但具有无 junk 元素出现在块中的额外限制。然后,通过在 2 侧匹配 (仅) junk 元素尽可能扩展该块。因此,结果块从不匹配 junk,除因为恒等 junk 与感兴趣匹配发生相邻外。
这里是如之前的相同范例,但考虑到 Blank 是 junk。阻止
'
abcd'
匹配
'
abcd'
直接在第 2 序列末尾。相反,仅
'abcd'
可以匹配,并匹配最左边的
'abcd'
在第 2 序列:
>>> s = SequenceMatcher(lambda x: x==" ", " abcd", "abcd abcd")
>>> s.find_longest_match(0, 5, 0, 9)
Match(a=1, b=0, size=4)
若没有块匹配,这返回
(alo,
blo,
0)
.
此方法返回
命名元组
Match(a,
b,
size)
.
get_matching_blocks
(
)
¶
返回描述非重叠匹配子序列的 3 元组列表。每 3 元组形式
(i,
j,
n)
,并意味着
a[i:i+n]
==
b[j:j+n]
。3 元组单调递增在
i
and
j
.
最后 3 元组是虚设的,且拥有值
(len(a),
len(b),
0)
。它是唯一 3 元组具有
n
==
0
。若
(i,
j,
n)
and
(i',
j',
n')
是相邻列表 3 元组,且第 2 个不是最后列表 3 元组,则
i+n
<
i'
or
j+n
<
j'
;换句话说,相邻 3 元组总是描述不相邻相等块。
>>> 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
(
)
¶
返回 5 元组列表描述如何转换
a
into
b
。每元组形式
(tag,
i1,
i2,
j1,
j2)
。第 1 个元组拥有
i1
==
j1
==
0
,和剩余元组拥有
i1
等于
i2
来自之前元组,同样,
j1
等于先前
j2
.
tag 值是字符串,具有这些含义:
| Value | 含义 |
|---|---|
'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'
get_grouped_opcodes
(
n=3
)
¶
返回 generator 为组具有最多 n 行的上下文。
从组开始返回通过
get_opcodes()
,此方法分割更小变化集群,并消除没有变化的干预范围。
以相同格式返回的组如同
get_opcodes()
.
ratio
(
)
¶
以 [0, 1] 范围浮点数返回序列相似性度量。
其中 T 是 2 序列的元素总数,M 是匹配数,这是 2.0 * M/T。注意,这是
1.0
若序列恒等,和
0.0
若它们没有共同之处。
这种计算是很昂贵的若
get_matching_blocks()
or
get_opcodes()
尚未被调用,在此情况下,可能想要尝试
quick_ratio()
or
real_quick_ratio()
首先获取上限。
返回匹配与总字符比率的 3 方法 (由于近似级别不同) 可以给出不同的结果,虽然
quick_ratio()
and
real_quick_ratio()
始终至少大于
ratio()
:
>>> s = SequenceMatcher(None, "abcd", "bcde")
>>> s.ratio()
0.75
>>> s.quick_ratio()
0.75
>>> s.real_quick_ratio()
1.0
此范例比较 2 字符串,并认为 Blank 是 junk:
>>> 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
.
若想要知道如何将第 1 序列更改成第 2 序列,使用
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
生成增量不声称是
minimal
diff。相反,最小 diff 经常反直觉,因为它们尽可能同步,有时却意外相距 100 页。将同步点限定到连续匹配可预留一些局域性概念,以偶尔产生更长 diff 为代价。
Differ
类拥有此构造函数:
difflib.
Differ
(
linejunk=None
,
charjunk=None
)
可选关键词参数
linejunk
and
charjunk
是过滤函数 (或
None
):
linejunk
:函数接受单字符串自变量并返回 True 若字符串是 junk。默认为
None
,意味着没有行被认为是 junk。
charjunk
:函数接受单字符自变量 (1 长字符串) 并返回 True 若字符是 junk。默认为
None
,意味着没有字符被认为是 junk。
这些 junk 过滤函数加速匹配以查找差异,且不会导致任何不同行或字符被忽略。阅读描述从
find_longest_match()
方法的
isjunk
参数为解释。
Differ
对象的使用 (生成增量) 是凭借一方法:
compare
(
a
,
b
)
¶
比较 2 行序列,并生成增量 (行序列)。
每序列必须包含以换行符结尾的单个单行字符串。这种序列可以获取自
readlines()
方法在像文件对象。生成增量也由以换行终止的字符串组成,准备按原样打印凭借
writelines()
方法在像文件对象。
此范例比较 2 文本。首先,设置文本,以换行符结尾的单个单行字符串序列 (这种序列还可以获取自
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
对象,可以传递函数以过滤掉行和 junk 字符。见
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.
此范例展示如何使用 difflib 来创建
diff
类似实用程序。它包含在 Python 源代码分发中,作为
Tools/scripts/diff.py
.
#!/usr/bin/env python3
""" Command line interface to difflib.py providing diffs in four formats:
* ndiff: lists every line and highlights interline changes.
* context: highlights clusters of changes in a before/after format.
* unified: highlights clusters of changes in an inline format.
* html: generates side by side comparison with change highlights.
"""
import sys, os, difflib, argparse
from datetime import datetime, timezone
def file_mtime(path):
t = datetime.fromtimestamp(os.stat(path).st_mtime,
timezone.utc)
return t.astimezone().isoformat()
def main():
parser = argparse.ArgumentParser()
parser.add_argument('-c', action='store_true', default=False,
help='Produce a context format diff (default)')
parser.add_argument('-u', action='store_true', default=False,
help='Produce a unified format diff')
parser.add_argument('-m', action='store_true', default=False,
help='Produce HTML side by side diff '
'(can use -c and -l in conjunction)')
parser.add_argument('-n', action='store_true', default=False,
help='Produce a ndiff format diff')
parser.add_argument('-l', '--lines', type=int, default=3,
help='Set number of context lines (default 3)')
parser.add_argument('fromfile')
parser.add_argument('tofile')
options = parser.parse_args()
n = options.lines
fromfile = options.fromfile
tofile = options.tofile
fromdate = file_mtime(fromfile)
todate = file_mtime(tofile)
with open(fromfile) as ff:
fromlines = ff.readlines()
with open(tofile) as tf:
tolines = tf.readlines()
if options.u:
diff = difflib.unified_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
elif options.n:
diff = difflib.ndiff(fromlines, tolines)
elif options.m:
diff = difflib.HtmlDiff().make_file(fromlines,tolines,fromfile,tofile,context=options.c,numlines=n)
else:
diff = difflib.context_diff(fromlines, tolines, fromfile, tofile, fromdate, todate, n=n)
sys.stdout.writelines(diff)
if __name__ == '__main__':
main()