批量处理文件,除了 Python,不妨试试 VIM!
在之前的辦公自動化系列文章,我們大多基于 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內容結構如下:
<vsbimg?src="/_vsl/012A716D176AFA6EBBAF64BD4CB63BCA/994A4168/AE5BB"></vsbimg> <vsbimg?src="/_vsl/2ADBFFCE33AAE9B2E79E758EF6AD5626/CEFD12BB/A8DC5"></vsbimg>要求是:
將 <vsbimg></vsbimg> 標簽改為 <img></img> 標簽。
將 /_vsl/012A7 表示的相對地址,變成另一個 URL 地址,如 http://image.xx.com/image/。
將 src 的最后兩個/改為 _。
將整個 src 最后加上圖片后綴 .png。
修改后的文件為:
<img?src="http://image.xx.com/image/16D176AFA6EBBAF64BD4CB63BCA_994A4168_AE5BB.png"></img> <img?src="http://image.xx.com/image/FCE33AAE9B2E79E758EF6AD5626_CEFD12BB_A8DC5.png"></img>02
Python實現
首先讓我們用 Python 編寫程序來完成,代碼比較簡單,但面對如此簡單的問題,寫一個程序還是“高射炮打蚊子” 了。而且調試 Python 正則表達式,并不是一個直觀的過程。
殺雞不用牛刀,咱們改用 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/g3.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 不是萬能的——至少在某些方面、某些場景下,不一定是最優解。合適的工具運用到合適的場合是效率最高的方式。不能自已是錘子,看什么就都是釘子。
推薦閱讀
Pandas處理數據太慢,來試試Polars吧!
懶人必備!只需一行代碼,就能導入所有的Python庫
絕!關于pip的15個使用小技巧
介紹10個常用的Python內置函數,99.99%的人都在用!
可能是全網最完整的 Python 操作 Excel庫總結!
總結
以上是生活随笔為你收集整理的批量处理文件,除了 Python,不妨试试 VIM!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 5行Python实现验证码识别,太稳了!
- 下一篇: B站疯传,年度数据分析+Python资料