python difflib --- 計算差異的輔助工具

此模塊提供用于比較序列的類和函數。 例如,它可被用于比較文件,并可產生多種格式的不同文件差異信息,包括 HTML 和上下文以及統一的 diff 數據。 有關比較目錄和文件,另請參閱?filecmp?模塊。

class?difflib.SequenceMatcher

這是一個靈活的類,可用于比較任何類型的序列對,只要序列元素為?hashable?對象。 其基本算法要早于由 Ratcliff 和 Obershelp 于 1980 年代末期發表并以“格式塔模式匹配”的夸張名稱命名的算法,并且更加有趣一些。 其思路是找到不包含“垃圾”元素的最長連續匹配子序列;所謂“垃圾”元素是指其在某種意義上沒有價值,例如空白行或空白符。 (處理垃圾元素是對 Ratcliff 和 Obershelp 算法的一個擴展。) 然后同樣的思路將遞歸地應用于匹配序列的左右序列片段。 這并不能產生最小編輯序列,但確實能產生在人們看來“正確”的匹配。

耗時:?基本 Ratcliff-Obershelp 算法在最壞情況下為立方時間而在一般情況下為平方時間。?SequenceMatcher?在最壞情況下為平方時間而在一般情況下的行為受到序列中有多少相同元素這一因素的微妙影響;在最佳情況下則為線性時間。

自動垃圾啟發式計算:?SequenceMatcher?支持使用啟發式計算來自動將特定序列項視為垃圾。 這種啟發式計算會統計每個單獨項在序列中出現的次數。 如果某一項(在第一項之后)的重復次數超過序列長度的 1% 并且序列長度至少有 200 項,該項會被標記為“熱門”并被視為序列匹配中的垃圾。 這種啟發式計算可以通過在創建?SequenceMatcher?時將?autojunk?參數設為?False?來關閉。

在 3.2 版本發生變更:?增加了?autojunk?形參。

class?difflib.Differ

這個類的作用是比較由文本行組成的序列,并產生可供人閱讀的差異或增量信息。 Differ 統一使用?SequenceMatcher?來完成行序列的比較以及相似(接近匹配)行內部字符序列的比較。

Differ?增量的每一行均以雙字母代碼打頭:

雙字母代碼

含意

'-?'

行為序列 1 所獨有

'+?'

行為序列 2 所獨有

'??'

行在兩序列中相同

'??'

行不存在于任一輸入序列

以 '?' 打頭的行嘗試將視線紖至行以外而不存在于任一輸入序列的差異。 如果序列包含空白符,例如空格、制表或換行則這些行可能會令人感到迷惑。

class?difflib.HtmlDiff

這個類可用于創建 HTML 表格(或包含表格的完整 HTML 文件)以并排地逐行顯示文本比較,行間與行外的更改將突出顯示。 此表格可以基于完全或上下文差異模式來生成。

這個類的構造函數:

__init__(tabsize=8,?wrapcolumn=None,?linejunk=None,?charjunk=IS_CHARACTER_JUNK)

初始化?HtmlDiff?的實例。

tabsize?是一個可選關鍵字參數,指定制表位的間隔,默認值為?8

wrapcolumn?是一個可選關鍵字參數,指定行文本自動打斷并換行的列位置,默認值為?None?表示不自動換行。

linejunk?和?charjunk?均是可選關鍵字參數,會傳入?ndiff()?(被?HtmlDiff?用來生成并排顯示的 HTML 差異)。 請參閱?ndiff()?文檔了解參數默認值及其說明。

下列是公開的方法

make_file(fromlines,?tolines,?fromdesc='',?todesc='',?context=False,?numlines=5,?*,?charset='utf-8')

比較?fromlines?和?tolines?(字符串列表) 并返回一個字符串,表示一個完整 HTML 文件,其中包含各行差異的表格,行間與行外的更改將突出顯示。

fromdesc?和?todesc?均是可選關鍵字參數,指定來源/目標文件的列標題字符串(默認均為空白字符串)。

context?和?numlines?均是可選關鍵字參數。 當只要顯示上下文差異時就將?context?設為?True,否則默認值?False?為顯示完整文件。?numlines?默認為?5。 當?context?為?True?時?numlines?將控制圍繞突出顯示差異部分的上下文行數。 當?context?為?False?時?numlines?將控制在使用 "next" 超鏈接時突出顯示差異部分之前所顯示的行數(設為零則會導致 "next" 超鏈接將下一個突出顯示差異部分放在瀏覽器頂端,不添加任何前導上下文)。

備注

fromdesc?和?todesc?會被當作未轉義的 HTML 來解讀,當接收不可信來源的輸入時應該適當地進行轉義。

在 3.5 版本發生變更:?增加了?charset?關鍵字參數。 HTML 文檔的默認字符集從?'ISO-8859-1'?更改為?'utf-8'

make_table(fromlines,?tolines,?fromdesc='',?todesc='',?context=False,?numlines=5)

比較?fromlines?和?tolines?(字符串列表) 并返回一個字符串,表示一個包含各行差異的完整 HTML 表格,行間與行外的更改將突出顯示。

此方法的參數與?make_file()?方法的相同。

difflib.context_diff(a,?b,?fromfile='',?tofile='',?fromfiledate='',?tofiledate='',?n=3,?lineterm='\n')

比較?a?和?b?(字符串列表);返回上下文差異格式的增量信息 (一個產生增量行的?generator)。

所謂上下文差異是一種只顯示有更改的行再加幾個上下文行的緊湊形式。 更改被顯示為之前/之后的樣式。 上下文行數由?n?設定,默認為三行。

默認情況下,差異控制行(以?***?or?---?表示)是通過末尾換行符來創建的。 這樣做的好處是從?io.IOBase.readlines()?創建的輸入將得到適用于?io.IOBase.writelines()?的差異信息,因為輸入和輸出都帶有末尾換行符。

對于沒有末尾換行符的輸入,應將?lineterm?參數設為?"",這樣輸出內容將統一不帶換行符。

上下文差異格式通常帶有一個記錄文件名和修改時間的標頭。 這些信息的部分或全部可以使用字符串?fromfile,?tofile,?fromfiledate?和?tofiledate?來指定。 修改時間通常以 ISO 8601 格式表示。 如果未指定,這些字符串默認為空。

>>>

>>> import sys
>>> from difflib import *
>>> 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
! hamguido
--- 1,4 ----
! python
! eggy
! hamsterguido

請參閱?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?和?b?(字符串列表);返回?Differ?形式的增量信息 (一個產生增量行的?generator)。

可選關鍵字形參?linejunk?和?charjunk?均為過濾函數 (或為?None):

linejunk: 此函數接受單個字符串參數,如果其為垃圾字符串則返回真值,否則返回假值。 默認為?None。 此外還有一個模塊層級的函數?IS_LINE_JUNK(),它會過濾掉沒有可見字符的行,除非該行添加了至多一個井號符 ('#') -- 但是下層的?SequenceMatcher?類會動態分析哪些行的重復頻繁到足以形成噪音,這通常會比使用此函數的效果更好。

charjunk: 此函數接受一個字符(長度為 1 的字符串),如果其為垃圾字符則返回真值,否則返回假值。 默認為模塊層級的函數?IS_CHARACTER_JUNK(),它會過濾掉空白字符(空格符或制表符;但包含換行符可不是個好主意!)。

>>>

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

返回兩個序列中產生增量的那一個。

給出一個由?Differ.compare()?或?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?和?b?(字符串列表);返回統一差異格式的增量信息 (一個產生增量行的?generator)。

所以統一差異是一種只顯示有更改的行再加幾個上下文行的緊湊形式。 更改被顯示為內聯的樣式(而不是分開的之前/之后文本塊)。 上下文行數由?n?設定,默認為三行。

默認情況下,差異控制行 (以?---,?+++?或?@@?表示) 是通過末尾換行符來創建的。 這樣做的好處是從?io.IOBase.readlines()?創建的輸入將得到適用于?io.IOBase.writelines()?的差異信息,因為輸入和輸出都帶有末尾換行符。

對于沒有末尾換行符的輸入,應將?lineterm?參數設為?"",這樣輸出內容將統一不帶換行符。

統一的差異格式通常帶有一個記錄文件名和修改時間的標頭。 這些信息的部分或全部可以使用字符串?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
+hamsterguido

請參閱?difflib 的命令行接口?獲取更詳細的示例。

difflib.diff_bytes(dfunc,?a,?b,?fromfile=b'',?tofile=b'',?fromfiledate=b'',?tofiledate=b'',?n=3,?lineterm=b'\n')

使用?dfunc?比較?a?和?b?(字節串對象列表);產生以?dfunc?所返回格式表示的差異行列表(也是字節串)。?dfunc?必須是可調用對象,通常為?unified_diff()?或?context_diff()。

允許你比較編碼未知或不一致的數據。 除?n?之外的所有輸入都必須為字節串對象而非字符串。 作用方式為無損地將所有輸入 (除?n?之外) 轉換為字符串,并調用?dfunc(a,?b,?fromfile,?tofile,?fromfiledate,?tofiledate,?n,?lineterm)。?dfunc?的輸出會被隨即轉換回字節串,這樣你所得到的增量行將具有與?a?和?b?相同的未知/不一致編碼。

在 3.5 版本加入.

difflib.IS_LINE_JUNK(line)

對于可忽略的行返回?True。 如果?line?為空行或只包含單個?'#'?則?line?行就是可忽略的,否則就是不可忽略的。 此函數被用作較舊版本?ndiff()?中?linejunk?形參的默認值。

difflib.IS_CHARACTER_JUNK(ch)

對于可忽略的字符返回?True。 字符?ch?如果為空格符或制表符則?ch?就是可忽略的,否則就是不可忽略的。 此函數被用作?ndiff()?中?charjunk?形參的默認值。

參見

Pattern Matching: The Gestalt Approach

John W. Ratcliff 和 D. E. Metzener 對于一種類似算法的討論。 此文于 1988 年 7 月發表于?Dr. Dobb's Journal。

SequenceMatcher 對象

SequenceMatcher?類具有這樣的構造器:

class?difflib.SequenceMatcher(isjunk=None,?a='',?b='',?autojunk=True)

可選參數?isjunk?必須為?None?(默認值) 或為接受一個序列元素并當且僅當其為應忽略的“垃圾”元素時返回真值的單參數函數。 傳入?None?作為?isjunk?的值就相當于傳入?lambda?x:?False;也就是說不忽略任何值。 例如,傳入:

lambda x: x in " \t"

如果你以字符序列的形式對行進行比較,并且不希望區分空格符或硬制表符。

可選參數?a?和?b?為要比較的序列;兩者默認為空字符串。 兩個序列的元素都必須為?hashable。

可選參數?autojunk?可用于啟用自動垃圾啟發式計算。

在 3.2 版本發生變更:?增加了?autojunk?形參。

SequenceMatcher 對象接受三個數據屬性:?bjunk?是?b?當中?isjunk?為?True?的元素集合;bpopular?是被啟發式計算(如果其未被禁用)視為熱門候選的非垃圾元素集合;b2j?是將?b?當中剩余元素映射到一個它們出現位置列表的字典。 所有三個數據屬性將在?b?通過?set_seqs()?或?set_seq2()?重置時被重置。

在 3.2 版本加入:?bjunk?和?bpopular?屬性。

SequenceMatcher?對象具有以下方法:

set_seqs(a,?b)

設置要比較的兩個序列。

SequenceMatcher?計算并緩存有關第二個序列的詳細信息,這樣如果你想要將一個序列與多個序列進行比較,可使用?set_seq2()?一次性地設置該常用序列并重復地對每個其他序列各調用一次?set_seq1()。

set_seq1(a)

設置要比較的第一個序列。 要比較的第二個序列不會改變。

set_seq2(b)

設置要比較的第二個序列。 要比較的第一個序列不會改變。

find_longest_match(alo=0,?ahi=None,?blo=0,?bhi=None)

找出?a[alo:ahi]?和?b[blo:bhi]?中的最長匹配塊。

如果?isjunk?被省略或為?None,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?當中最先出現的一個。

>>>

>>> s = SequenceMatcher(None, " abcd", "abcd abcd")
>>> s.find_longest_match(0, 5, 0, 9)
Match(a=0, b=4, size=5)

如果提供了?isjunk,將按上述規則確定第一個最長匹配塊,但額外附加不允許塊內出現垃圾元素的限制。 然后將通過(僅)匹配兩邊的垃圾元素來盡可能地擴展該塊。 這樣結果塊絕對不會匹配垃圾元素,除非同樣的垃圾元素正好與有意義的匹配相鄰。

這是與之前相同的例子,但是將空格符視為垃圾。 這將防止?'?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)

如果未找到匹配塊,此方法將返回?(alo,?blo,?0)

此方法將返回一個?named tuple?Match(a,?b,?size)

在 3.9 版本發生變更:?加入默認參數。

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

get_opcodes()

返回描述如何將?a?變為?b?的 5 元組列表,每個元組的形式為?(tag,?i1,?i2,?j1,?j2)。 在第一個元組中?i1?==?j1?==?0,而在其余的元組中?i1?等于前一個元組的?i2,并且?j1?也等于前一個元組的?j2

tag?值為字符串,其含義如下:

含意

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

返回一個帶有最多?n?行上下文的分組的?generator。

從?get_opcodes()?所返回的組開始,此方法會拆分出較小的更改簇并消除沒有更改的間隔區域。

這些分組以與?get_opcodes()?相同的格式返回。

ratio()

返回一個取值范圍 [0, 1] 的浮點數作為序列相似性度量。

其中 T 是兩個序列中元素的總數量,M 是匹配的數量,即 2.0*M / T。 請注意如果兩個序列完全相同則該值為?1.0,如果兩者完全不同則為?0.0

如果?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

SequenceMatcher 的示例

以下示例比較兩個字符串,并將空格視為“垃圾”:

>>>

>>> 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?的唯一情況。

如果你想要知道如何將第一個序列轉成第二個序列,可以使用?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 對象

請注意?Differ?所生成的增量并不保證是?最小?差異。 相反,最小差異往往是違反直覺的,因為它們會同步任何可能的地方,有時甚至意外產生相距 100 頁的匹配。 將同步點限制為連續匹配保留了一些局部性概念,這偶爾會帶來產生更長差異的代價。

Differ?類具有這樣的構造器:

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

可選關鍵字形參?linejunk?和?charjunk?均為過濾函數 (或為?None):

linejunk: 接受單個字符串作為參數的函數,如果其為垃圾字符串則返回真值。 默認值為?None,意味著沒有任何行會被視為垃圾行。

charjunk: 接受單個字符(長度為 1 的字符串)作為參數的函數,如果其為垃圾字符則返回真值。 默認值為?None,意味著沒有任何字符會被視為垃圾字符。

這些垃圾過濾函數可加快查找差異的匹配速度,并且不會導致任何差異行或字符被忽略。 請閱讀?find_longest_match()?方法的?isjunk?形參的描述了解詳情。

Differ?對象是通過一個單獨方法來使用(生成增量)的:

compare(a,?b)

比較兩個由行組成的序列,并生成增量(一個由行組成的序列)。

每個序列必須包含一個以換行符結尾的單行字符串。 這樣的序列可以通過文件型對象的?readlines()?方法來獲取。 所生成的增量同樣由以換行符結尾的字符串構成,可以通過文件型對象的?writelines()?方法原樣打印出來。

Differ 示例

此示例比較兩段文本。 首先我們設置文本為以換行符結尾的單行字符串組成的序列(這樣的序列也可以通過文件型對象的?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?對象時我們可以傳入函數來過濾掉“垃圾”行和字符。 詳情參見?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 的命令行接口

這個例子演示了如何使用 difflib 來創建類似?diff?的工具。

""" 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, timezonedef 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.linesfromfile = options.fromfiletofile = options.tofilefromdate = 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()

ndiff 示例

這個例子演示了如何使用?difflib.ndiff()。

"""ndiff [-q] file1 file2or
ndiff (-r1 | -r2) < ndiff_output > file1_or_file2Print a human-friendly file difference report to stdout.  Both inter-
and intra-line differences are noted.  In the second form, recreate file1
(-r1) or file2 (-r2) on stdout, from an ndiff report on stdin.In the first form, if -q ("quiet") is not specified, the first two lines
of output are-: file1
+: file2Each remaining line begins with a two-letter code:"- "    line unique to file1"+ "    line unique to file2"  "    line common to both files"? "    line not present in either input fileLines beginning with "? " attempt to guide the eye to intraline
differences, and were not present in either input file.  These lines can be
confusing if the source files contain tab characters.The first file can be recovered by retaining only lines that begin with
"  " or "- ", and deleting those 2-character prefixes; use ndiff with -r1.The second file can be recovered similarly, but by retaining only "  " and
"+ " lines; use ndiff with -r2; or, on Unix, the second file can be
recovered by piping the output throughsed -n '/^[+ ] /s/^..//p'
"""__version__ = 1, 7, 0import difflib, sysdef fail(msg):out = sys.stderr.writeout(msg + "\n\n")out(__doc__)return 0# open a file & return the file object; gripe and return 0 if it
# couldn't be opened
def fopen(fname):try:return open(fname)except IOError as detail:return fail("couldn't open " + fname + ": " + str(detail))# open two files & spray the diff to stdout; return false iff a problem
def fcompare(f1name, f2name):f1 = fopen(f1name)f2 = fopen(f2name)if not f1 or not f2:return 0a = f1.readlines(); f1.close()b = f2.readlines(); f2.close()for line in difflib.ndiff(a, b):print(line, end=' ')return 1# crack args (sys.argv[1:] is normal) & compare;
# return false iff a problemdef main(args):import getopttry:opts, args = getopt.getopt(args, "qr:")except getopt.error as detail:return fail(str(detail))noisy = 1qseen = rseen = 0for opt, val in opts:if opt == "-q":qseen = 1noisy = 0elif opt == "-r":rseen = 1whichfile = valif qseen and rseen:return fail("can't specify both -q and -r")if rseen:if args:return fail("no args allowed with -r option")if whichfile in ("1", "2"):restore(whichfile)return 1return fail("-r value must be 1 or 2")if len(args) != 2:return fail("need 2 filename args")f1name, f2name = argsif noisy:print('-:', f1name)print('+:', f2name)return fcompare(f1name, f2name)# read ndiff output from stdin, and print file1 (which=='1') or
# file2 (which=='2') to stdoutdef restore(which):restored = difflib.restore(sys.stdin.readlines(), which)sys.stdout.writelines(restored)if __name__ == '__main__':main(sys.argv[1:])

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/715242.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/715242.shtml
英文地址,請注明出處:http://en.pswp.cn/news/715242.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

WebAssembly 是啥東西

WebAssembly&#xff08;簡稱Wasm&#xff09;是一種為網絡瀏覽器設計的二進制指令格式&#xff0c;它旨在成為一個高效的編程語言的編譯目標&#xff0c;從而允許在網絡上部署客戶端和服務器應用程序。WebAssembly的主要設計目標是實現高性能應用&#xff0c;同時維持網絡的安…

GraphPad Prism 10: 你的數據,我們的魔法 mac/win版

GraphPad Prism 10是GraphPad Software公司推出的一款功能強大的數據分析和可視化軟件。它集數據整理、統計分析、圖表制作和報告生成于一體&#xff0c;為科研工作者、學者和數據分析師提供了一個高效、便捷的工作平臺。 GraphPad Prism 10軟件獲取 Prism 10擁有豐富的圖表類…

2023義烏最全“電商+跨境+直播”數據總結篇章!

值得收藏&#xff5c;2023義烏最全“電商跨境直播”數據總結篇章&#xff01; 麥琪享資訊2024-01-20 14:28浙江 新年伊始&#xff0c;央視就把鏡頭對準了義烏電商&#xff0c;以電商的蓬勃之勢展現這座國際商城的開放與活力。 過去的一年 義烏電商量質齊升 實力出圈 跑出了…

nginx 根據參數動態代理

一、問題描述 nginx反向代理配置一般都是配置靜態地址&#xff0c;比如&#xff1a; server {listen 80;location / {proxy_pass http://myapp1;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}} 這個反向代理表示訪問80端口跳轉到 http://myapp1 …

騰訊云優惠券領取入口_先領取再下單_2024騰訊云優惠攻略

騰訊云優惠代金券領取入口共三個渠道&#xff0c;騰訊云新用戶和老用戶均可領取8888元代金券&#xff0c;可用于云服務器等產品購買、續費和升級使用&#xff0c;阿騰云atengyun.com整理騰訊云優惠券&#xff08;代金券&#xff09;領取入口、代金券查詢、優惠券兌換碼使用方法…

在Windows下運行命令行程序,如何才能不顯示命令行窗口,讓程序保持后臺運行?

在Windows下&#xff0c;有幾種方法可以使命令行程序在后臺運行而不顯示命令行窗口。以下是其中的一些方法&#xff1a; 一. 使用start命令 你可以使用start命令來啟動程序&#xff0c;并將窗口樣式設置為最小化。例如&#xff1a; cmd start /b your_program.exe這里的/b選…

【硬件相關】IB網/以太網基礎介紹及部署實踐

文章目錄 一、前言1、Infiniband網絡1.1、網絡類型1.2、網絡拓撲1.3、硬件設備1.3.1、網卡1.3.2、連接線纜a、光模塊b、線纜 1.3.4、交換機 2、Ethernet網絡 二、部署實踐&#xff08;以太網&#xff09;1、Intel E810-XXVDA21.1、網卡信息1.2、檢查命令1.2、驅動編譯 2、Mella…

volatile 關鍵字 (二)

volatile 關鍵字 &#xff08;二&#xff09; 文章目錄 volatile 關鍵字 &#xff08;二&#xff09;volatile 可以保證原子性么&#xff1f; 文章來自Java Guide 用于學習如有侵權&#xff0c;立即刪除 volatile 可以保證原子性么&#xff1f; volatile 關鍵字能保證變量的可…

nextjs中_app.tsx下劃線什么作用

在Next.js中&#xff0c;_app.tsx&#xff08;或_app.js&#xff09;是一個特殊的文件&#xff0c;用于初始化頁面。下劃線_前綴在文件名中具有特定的意義&#xff0c;它告訴Next.js這個文件是一個特殊的內置文件&#xff0c;用于覆蓋或擴展默認的App行為。 具體來說&#xff…

Python 潮流周刊第 40 期(摘要)

本周刊由 Python貓 出品&#xff0c;精心篩選國內外的 250 信息源&#xff0c;為你挑選最值得分享的文章、教程、開源項目、軟件工具、播客和視頻、熱門話題等內容。愿景&#xff1a;幫助所有讀者精進 Python 技術&#xff0c;并增長職業和副業的收入。 周刊全文&#xff1a;h…

C++_數據結構_數據的輸入

作用 用于從鍵盤獲取數據 關鍵字 cin >> 變量示例

YOLOv5論文作圖教程(3)— 關于論文作圖教程系列采用線上培訓的通知(終結篇)

前言:Hello大家好,我是小哥談。YOLOv5論文作圖教程系列其實是我特別擅長的一個模塊(本人產品經理出身),自從本系列發表了兩篇文章之后,一直沒有再繼續更新,主要原因是通過文字無法比較好的表達軟件的功能及使用,并且也無法達到比較好的培訓效果。為了確保大家可以徹底掌…

數據庫原理(一)

1、基本概念 學號姓名性別出生年月籍貫220101張三男2003江蘇220102李四男2003山東220103王五女2003河北220104趙六女2003天津220105張四男2003北京220106李五女2003江蘇220107王六女2003山東220108張七男2003河北220109張九男2003天津220110李十女2003北京 1.1數據&#xff0…

基于springboot+vue的相親網站

博主主頁&#xff1a;貓頭鷹源碼 博主簡介&#xff1a;Java領域優質創作者、CSDN博客專家、阿里云專家博主、公司架構師、全網粉絲5萬、專注Java技術領域和畢業設計項目實戰&#xff0c;歡迎高校老師\講師\同行交流合作 ?主要內容&#xff1a;畢業設計(Javaweb項目|小程序|Pyt…

軟考54-上午題-【數據庫】-關系模式的范式-真題

一、范式總結 第一步&#xff0c;先求候選碼&#xff0c;由此得到&#xff1a;主屬性、非主屬性。 二、判斷部分函數依賴的技巧 【回顧】&#xff1a;部分函數依賴 &#xff08;X&#xff0c;Y&#xff09;——>Z&#xff1b; X——>Z 或者 Y——>Z 題型&#xff1a;給…

全量知識系統問題及SmartChat給出的答復 之13 解析器+DDD+文法型 之2

Q36. 知識系統中設計的三種文法解析器和設計模式之間的關系 進一步&#xff0c;我想將 知識系統中設計的三種語言&#xff08;形式語言、人工語言和自然&#xff09;的文法解析器和DDD中的三種程序類型&#xff08;領域模型、領域實體和領域服務&#xff09; 形式語言文法 我…

Java中的圖數據庫應用:Neo4j入門

第1章&#xff1a;引言 在數據驅動的時代&#xff0c;咱們處理的不僅僅是數字和文本&#xff0c;還有復雜的關系和網絡。想象一下社交網絡中人與人之間錯綜復雜的聯系&#xff0c;或者是互聯網上網頁之間的鏈接關系&#xff0c;傳統的表格數據庫已經難以高效地處理這些關系密集…

每日leetcode--最大數

正題之前 三玖yyds&#xff01;&#xff01;&#xff01; 題目 給定一組非負整數 nums&#xff0c;重新排列每個數的順序&#xff08;每個數不可拆分&#xff09;使之組成一個最大的整數。 注意&#xff1a;輸出結果可能非常大&#xff0c;所以你需要返回一個字符串而不是整…

籃球游戲中的挑戰精神與慪氣心理:扣籃被帽后的再度沖擊

在籃球比賽中&#xff0c;扣籃無疑是最具觀賞性和震撼力的動作之一&#xff0c;它展示了球員的爆發力、技巧和自信。而在籃球游戲中&#xff0c;玩家即便面臨連續扣籃被蓋帽的挫折&#xff0c;仍渴望繼續殺入內線嘗試扣籃的現象&#xff0c;實則是體育競技精神、挑戰意識與慪氣…

梵寧教育:警惕網絡詐騙,守護青春未來

隨著互聯網的普及和科技的飛速發展&#xff0c;網絡已經深入到了我們生活的方方面面&#xff0c;為大學生提供了前所未有的便利與機遇。然而&#xff0c;與此同時&#xff0c;網絡詐騙也悄然滋生&#xff0c;成為威脅大學生安全的一大隱患。梵寧教育在此鄭重提醒廣大大學生&…