首頁 > 科技

批量處理檔案,除了 Python,不妨試試 VIM

2021-06-30 11:28:11

來源:早起Python

作者:大奎

大家好,我是早起。

在之前的辦公自動化系列文章,我們大多基於 Python 實現,因為使用 Python 具有靈活、強大的特點。使用 VIM 具有快速、視覺化的優勢。兩者對大量同構文字進行修改,可大幅提高工作效率。但相較於編寫 Python 程式,VIM 視覺化執行更勝一籌。

這也提示我們,Python 不是萬能的——至少在某些方面、某些場景下,不一定是最優解。合適的工具運用到合適的場合是效率最高的方式。不能自己是錘子,看什麼就都是釘子。

在對 VIM 不熟悉的使用者看來,VIM 的操作過程可能更復雜、難懂。但這是先入為主的印象,VIM 處理文字還是很方便快捷的:我們有了 Python 這把錘子,不排斥再來 VIM 這個鋸嘛,這樣才能「工欲善其事,必先利其器」。本文將對比使用 Python 和 VIM 對同一個文字編輯任務處理的情況。

01、需求說明

有大量類似結構的文字檔案需要處理,目錄結構如下:

E:.└─content ├─a │ └──content.txt ├─b │ └──content.txt └─c └──content.txt

其中的每個檔案 content .txt內容結構如下:

<vsbimgsrc="/_vsl/012A716D176AFA6EBBAF64BD4CB63BCA/994A4168/AE5BB"></vsbimg><vsbimgsrc="/_vsl/2ADBFFCE33AAE9B2E79E758EF6AD5626/CEFD12BB/A8DC5"></vsbimg>

要求是:

將 <vsbimg></vsbimg> 標籤改為 <img></img> 標籤。將 /_vsl/012A7 表示的相對地址,變成另一個 URL 地址,如 http://image.xx.com/image/。將 src 的最後兩個/改為 _。將整個 src 最後加上圖片字尾 .png。修改後的檔案為:

<imgsrc="http://image.xx.com/image/16D176AFA6EBBAF64BD4CB63BCA_994A4168_AE5BB.png"></img><imgsrc="http://image.xx.com/image/FCE33AAE9B2E79E758EF6AD5626_CEFD12BB_A8DC5.png"></img>

02、Python實現

首先讓我們用 Python 編寫程式來完成,程式碼比較簡單,但面對如此簡單的問題,寫一個程式還是「高射炮打蚊子」 了。而且偵錯 Python 正則表示式,並不是一個直觀的過程。

import osimport redefrep(strs): strs = re.sub(r'<vsbimg',r'<img',strs) strs = re.sub(r'</vsbimg',r'</img',strs) strs = re.sub(r'(/_vsl/.*?)/',r'1_',strs) strs = re.sub(r'(/_vsl/.*?)/',r'1_',strs) strs = re.sub(r'(src=".*?)"',r'1.png"',strs) strs = re.sub(r'src="/_vsl/.{5}',r'src="http://image.x.com/image/',strs) return strsdefop(fn): fn2 = os.path.join(os.path.split(fn)[0],os.path.split(fn)[1]+'new') with open(fn,encoding='utf-8') as f,open(fn2,'w',encoding='utf-8') as f2: for l in f.readlines(): l = rep(l) f2.write(l)for r,_,fs in os.walk('content'): for f in fs: if f.endswith('txt'): fn = os.path.join(r,f) op(fn)

殺雞不用牛刀,咱們改用 VIM 試試。

VIM 最主要好處就是:構造查詢正則表示式時結果視覺化,這樣就可以逐步求精地寫正則表示式,反之剛才寫程式時,我得來回測試,十分費力。

03、VIM實現

下面是使用 VIM 實現需求所需要注意的幾點

本例使用 VIM 中的 :%s 替換指令很容易完成替換操作。正則表示式構造需要慢慢來。如果牽涉到複雜替換時,還需要對搜尋結果分組,以便使用分組結果。為了批量完成序列替換操作,需要將操作寫入批處理指令碼,再用 :source 執行指令碼。以上操作在單檔案中執行,為了在許多檔案中同時完成,需要使用緩衝區執行 :bufdo 命令。3.1 構造正則表示式搜尋

為了替換 <vsbimg,我們構造一個查詢正則表示式。

構造出的表示式如下:

/<vsbimg

這個表示式搜尋了 <vsbimg 開頭的所有內容。

在 / 指令後按向上箭頭表示上一次輸入的查詢歷史。按 q/ 表示所有查詢歷史,可以在此歷史上修改,這樣就可以逐步精化。

3.2 替換

常規替換指令 :%s/pattern/string/g,留空的查詢域表示上次搜尋的結果。在上步查詢基礎上,我們可以使用 :%s//<img/g 的方式完成更改。

這個操作很重要:很多複雜的正則表示式,不可能一步直接構造出來;採用搜尋的方法,可以高亮顯示每次的搜尋結果,進而改進正則表示式。而替換時留空查詢域,直接表示上次搜尋結果,極大方便了替換操作。使一步替換操作轉換為:搜尋,替換兩步,降低了難度,提高了效率。

注意以下替換語句,使用了 轉義字元來匹配 </vsbimg> 的特殊字元 。

:%s/</vsbimg/</img/g

3.3 搜尋結果分組、使用

在對 轉換為 _ 的操作中,我們需要記住之前的匹配物件,用來在替換時作為不改變的內容引用。

這裡用 () 圈起來需要分組的部分,在搜尋或者替換部分用 1 表示第一個分組,以此類推。具體看程式碼:

:%s/("/_vsl/.{-1,})//1_/g

因為有兩個 ,所以需要執行兩次。

替換域裡的 1 指代的是 () 中的匹配內容,也就是 src 從 _vsb/ 之後遇到的第一個 為止的內容。當替換時,我們依然把這部分,用 1 使用上,只是把 改為_。

3.4 非貪婪模式

上例子可見 .{-1,} 的程式碼,這是對任意字元進行非貪婪匹配,以縮小 / 適配範圍,適配到第一個 / 為止,不再繼續貪婪最大適配。

在給 src 新增 .png 字尾時,也使用了分組和非貪婪概念。將 src 到第一個"的內容視為一個分組,然後替換為分組內容和 .png"。

:%s/(src=".{-1,})"/1.png"/g

將相對地址修改為 URL 時,URL 部分需要進行很多次轉義。

:%s/src="/_vsl/.{5}/src="http://192.168.22.117/cnv/jflyfox/mtg/cnvImage//g

最後,我們把以上修改儲存進原檔案:w。

以上,我們通過搜尋和替換操作,完成了對單個檔案的修改。

如果對每一個檔案都執行如上的程式,就顯得比較複雜了,好在 VIM 支援批處理操作。

3.5 批處理檔案執行 source

這裡,我們將以上操作步驟,寫到 oper.vim 檔案中去。

:%s/<vsbimg/<img/ge:%s/</vsbimg/</img/ge:%s/("/_vsl/.{-1,})//1_/ge:%s/("/_vsl/.{-1,})//1_/ge:%s/(src=".{-1,})"/1.png"/ge:%s/src="/_vsl/.{5}/src="http://192.168.22.117/cnv/jflyfox/mtg/cnvImage//ge:w

在另一個新的待處理檔案中,我們輸入 :source oper.vim,就將以上所有操作在新檔案中重做。

操作一個新檔案可行了,如何操作大批量的檔案呢?

按 q: 表示所有替換歷史,將這些替換命令拷貝出來,避免輸入帶來的麻煩和錯誤。

3.6 緩衝區批量執行 bufdo

VIM 的 Buffer 緩衝區,相當於記憶體。當我們具體修改某個檔案時,實際是在記憶體中對他進行修改,只有當輸入 :w 命令時,修改才寫回硬碟。

使用 vim a.txt b.txt 指令,一次性開啟兩個檔案,當前訪問和修改的是 a.txt。使用指令 :bnext 在緩衝區之間跳轉。指令 :ls 列出了當前所有緩衝區檔案。

使用 vim *.txt,批量開啟 txt 字尾的檔案。

在當前緩衝區列表上的所有檔案執行命令,輸入 :bufdo excommand。

本文中我們開啟目錄 a,b,c 下的 content.txt 檔案,使用 vim content/*/*.txt 即可。在開啟的視窗中執行 :ls 即可檢視當前緩衝區檔案。確認無誤後,執行 :bufdo source oper.vim ,即可完成對所有緩衝區檔案的修改。

抑制錯誤:當我們使用以上 vim 指令碼時,很容易因為搜尋規則或者文字問題導致出錯,進而導致指令碼停止。在每個替換語句之後加上 e ,用來表示抑制錯誤,就可以修正這個問題。

04、小結

使用 VIM 中的替換指令很容易完成操作。但正則表示式構造需要慢慢來。逐步求精,還可能需要分組和非貪婪模式。批處理檔案 .vim 和 :source 命令可以大大簡化工作。緩衝區列表執行 :bufdo 命令則進一步提高工作效率。

VIM 編輯器處理這個問題,使用的技巧都比較通用,可以遷移到其他文字處理任務中。最主要的是,構造正則表示式的過程是直接反饋、視覺化的,利於構造複雜表示式。

Python 不是萬能的——至少在某些方面、某些場景下,不一定是最優解。合適的工具運用到合適的場合是效率最高的方式。不能自已是錘子,看什麼就都是釘子。


IT145.com E-mail:sddin#qq.com