python diff函数_使用Python创建你自己的diff工具
為什么我需要自己的diff工具?
我經(jīng)常使用git跟蹤我的編碼項(xiàng)目、文章、業(yè)務(wù)工作等等。git的一個美妙之處在于,你可以通過簡單地使用其內(nèi)置的diff功能來輕松地比較你的工作的不同狀態(tài)。要使用這個功能,你只需要滿足兩個約束:首先,你需要一個git存儲庫,其次,該文件需要由git存儲庫進(jìn)行跟蹤。
但是,如果您只想修改單個文件,并將其與舊版本進(jìn)行比較,所有這些操作都不需要用到git存儲庫,那該怎么辦呢?這就是本文的意義所在。本文的目標(biāo)是創(chuàng)建一個diff工具,它允許你比較一個文件的兩個版本:
不需要git存儲庫和
構(gòu)建在Python標(biāo)準(zhǔn)庫之上!
此外,我們的diff工具應(yīng)該能夠?qū)⒂?jì)算的差異導(dǎo)出到一個HTML文件中。要閱讀這篇文章,你只需要會Python。本文是專門為Python 3.8.2 (CPython)編寫的。你可以在GitHub上找到源代碼。就介紹到這里,讓我們來看看它吧!
unified_diff() 函數(shù)
Python標(biāo)準(zhǔn)庫包含一個名為difflib的模塊。根據(jù)文檔,這個模塊提供了用于比較序列的類和函數(shù)。此外,還有各種可用的輸出格式[1]。
在檢查該模塊時,unified_diff()函數(shù)從所有其他函數(shù)中脫穎而出。通過查看文檔提供的示例和生成的輸出,我發(fā)現(xiàn)它與我們正在尋找的差異計(jì)算函數(shù)非常相似。它需要多達(dá)8個參數(shù),但只有兩個是必需的:
a:字符串列表(必需)
b:字符串列表(必需)
fromfile:用于顯示第一個文件的名稱(默認(rèn)值:'')
tofile:用于顯示第二個文件的名稱(默認(rèn)值:'' )
fromfiledate:第一個文件的修改時間(默認(rèn)值: '')
tofiledate:第二個文件的修改時間(默認(rèn)值: '')
n:上下文行數(shù)*(默認(rèn)值:3)
lineterm:添加在控制行(帶有—、+++或@@的行)末尾的字符,以便io.IOBase.readlines()和io.IOBase.writelines()能被正確處理(默認(rèn)值:'\n')。
*上下文行用于向用戶在發(fā)生更改的地方提供上下文
實(shí)際上,unified_diff()函數(shù)會接受兩個字符串列表并對它們進(jìn)行比較。如果它們是相等的,delta就為空。如果存在任何差異,則返回各自的delta。舉個簡單的例子:你打算和你最好的朋友一起舉辦一個披薩派對,然后寫下了你需要先買的配料。為簡單起見,此購物清單是一個簡單的文本文件(my_shopping_list.txt),內(nèi)容如下所示:
你把它發(fā)送給你的朋友,他加了一種配料,因?yàn)槟銈兗依锒紱]有了:salami(意大利臘腸)。此外,他還識別出了你的打字錯誤并進(jìn)行了糾正。為了能夠正確地將這些更改傳遞給我們的diff工具,他復(fù)制了該清單并將其重命名為friends_shopping_list.txt。以下是最終的購物清單:
當(dāng)然,這是一個相當(dāng)簡單的例子,文本不是很長,所以能很容易地被人為處理。但是,讓我們增加點(diǎn)樂趣,我們繼續(xù)看這個例子。為了計(jì)算這兩個文件之間的差異,我們將它們讀入內(nèi)存,并將它們傳遞給unified_diff()函數(shù):
首先,我們導(dǎo)入了difflib和sys。其次,我們讀取這兩個文件的內(nèi)容,并將它們保存到單獨(dú)的變量(file1和file2)中。因?yàn)槲覀冃枰址斜?#xff0c;所以我們使用了readlines()。隨后,我們計(jì)算了兩個列表的delta,并通過sys.stdout.writelines()將其寫到stdout。
執(zhí)行腳本后生成的結(jié)果如下:
從輸出來看,單詞cheese沒有被修改,而是被用作上下文行,因?yàn)橄旅娴男斜恍薷牧恕omates被移除了,tomatoes和salami被加了進(jìn)去。如果您查看打印出的delta的頭部,你可以看到,我們并沒有得到有關(guān)--- 和 +++代表什么,或者它們代表什么文件的任何信息。讓我們通過將文件名添加到unified_diff()函數(shù)來調(diào)整一下腳本:
現(xiàn)在,運(yùn)行該腳本生成結(jié)果如下:
太棒了!我們實(shí)現(xiàn)了一個簡單的腳本,它可以計(jì)算并打印兩個文件內(nèi)容之間的差異。讓我們繼續(xù)并將其轉(zhuǎn)換為一個命令行工具。
構(gòu)建一個命令行工具
為了將我們的腳本轉(zhuǎn)換成一個有用的命令行工具,我們使用了Python的argparse模塊。首先,我們將之前編寫的代碼放入一個名為create_diff()的函數(shù)中,該函數(shù)接受兩個參數(shù),old_file和new_file。它們都是Path對象[2]。我們使用傳遞的Path對象來讀取它們的內(nèi)容,并使用該P(yáng)ath對象的name屬性來獲取所提供的文件的名稱。由于我們的小腳本現(xiàn)在是要更加通用,不再局限于購物清單,所以我們將我們的代碼放入一個名為diff_tool.py的新文件中(這個名稱更適合我們的腳本)。到目前為止,該腳本是這樣的:
接著,我們定義一個新函數(shù)main(),它負(fù)責(zé)總的工作流:
首先,我們定義了一個新的參數(shù)解析器。我們告訴該解析器接受兩個參數(shù),old_file_version和new_file_version。兩者都是必需的。調(diào)用parse_args()將解析命令行輸入并將輸入轉(zhuǎn)換為正確的格式。隨后,兩個命令行參數(shù)都會被訪問并且被轉(zhuǎn)換為Path對象。然后,我們使用old_file和new_file作為參數(shù)調(diào)用create_diff()。
備注:如果您想要了解更多關(guān)于argparse模塊的內(nèi)容,我強(qiáng)烈推薦Python的argparse教程[3],它提供了更詳細(xì)的Python命令行解析介紹。
現(xiàn)在,如果我們不帶任何參數(shù)執(zhí)行該腳本,它會告訴我們,哪些參數(shù)是必需的:
提供兩個購物清單后仍然會生成預(yù)期的輸出:
到目前為止,我們通過將你的簡短腳本從頭開始轉(zhuǎn)換成一個簡單的命令行工具來構(gòu)建了一個簡單的diff工具—很酷!現(xiàn)在,我們將添加更多的行來支持HTML輸出。
以HMTL格式提供差異
difflib模塊提供了一個HtmlDiff類,它可以被用來創(chuàng)建一個HTML表(或一個包含表的完整HTML文件),該表會通過將行間和行內(nèi)變?yōu)楦吡溜@示來顯示文本的并排、逐行比較。在我們的示例中,我們使用了HtmlDiff.make_file()函數(shù),它返回了一個表示完整HTML文件的字符串。后者逐行高亮顯示了任何差異。
因此,我們將我們的腳本擴(kuò)展如下:
create_diff()函數(shù)現(xiàn)在接受一個額外的第三個參數(shù)output_file,它也是一個Path對象。我們會將我們的HTML差異寫入這個文件。我們檢查是否傳遞了output_file。如果是,我們以HTML格式計(jì)算差異并將其保存到這個傳遞的文件中。
備注:我們使用w模式進(jìn)行寫操作。如果該文件已經(jīng)存在,則會被提前清空。
如果output_file沒有被傳遞,我們會計(jì)算標(biāo)準(zhǔn)差異并將其寫到stdout。
我們通過注冊一個附加的可選命令行參數(shù)--html使其以一個文件名作為輸入來擴(kuò)展了main()函數(shù)。如果提供了文件名,則將其轉(zhuǎn)換為Path對象并傳遞給create_diff()。
執(zhí)行以下命令之后,您的當(dāng)前工作目錄中就有了一個diff.html文件,你可以使用你最喜歡的瀏覽器來打開該文件去查看實(shí)際的差異。
總結(jié)
恭喜,你已經(jīng)通過本文創(chuàng)建了它!在閱讀本文時,你了解了如何使用Python的difflib模塊計(jì)算一個簡單的diff。此外,你還能夠使用Python的argparse模塊將您的短小diff腳本轉(zhuǎn)換成一個命令行工具。隨后,你添加了幾行代碼來支持以HTML作為輸出格式。
接下來是什么?你可以查看difflib文檔[1],了解計(jì)算diff的各種方法,搜索其他類型的diff,并進(jìn)一步擴(kuò)展你的diff-tool。另外,你可以查看本文的GitHub存儲庫并計(jì)算file.md和file_update.md之間的差異。你找到所有的變化了嗎?
希望你喜歡閱讀這篇文章。一定要與你的朋友和同事進(jìn)行分享哦!如果你還沒有,你可以考慮關(guān)注我的推特@DahlitzF。保持好奇心,持續(xù)編碼!
參考資料
difflib文檔
Path文檔
argparse文檔
內(nèi)置open()函數(shù)
總結(jié)
以上是生活随笔為你收集整理的python diff函数_使用Python创建你自己的diff工具的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: k8s 查看mysql 日志_k8s 使
- 下一篇: websocket python爬虫_p