vim如何有效處理制式內容?
如我有以下資料
apple
bird
cat
dog
想要得到以下這樣的代碼
apple=listdata["name"]["apple"]
bird=listdata["name"]["bird"]
cat=listdata["name"]["cat"]
dog=listdata["name"]["dog"]
覺得一個一個複製再修改沒發揮到vim的強大功能,除了用正則表達式還有什麼辦法嗎?
用宏是正確的,對於行數不多的情況可以輕易完成。
但如果行數比較多,那麼宏就會很慢(就算是開啟了 lazyredraw )。我嘗試過對 10000 行左右的文本進行上述操作,已經有明顯的延遲。
通常情況下,這種任務是建議使用 awk 或者 sed 來完成。如果因為某些原因無法或者不方便用的,選擇 vim 來完成也是推薦使用正則表達式替換,而不是用宏,試試使用下面的替換命令,你可以看到處理速度的巨大差距,內容越多,差距越明顯:
:%s/.*/=listdata["name"][""]
不知道出於什麼原因,題主要求不使用正則表達式來完成,所以 %s 就無法使用。但是,我們還是有曲線救國的方法——利用 ex 命令和寄存器。
直接使用宏慢的原因在於所有的鍵入操作都需要不斷被重複,想要加快速度,那麼關鍵就是在於減少鍵入的次數。
在原來的宏中,我們需要鍵入 27 個按鍵。
ywA=listdata["name"]["&
重複次數越多的時候,所需要消耗的性能就越多。
所以,我們可以利用寄存器來保存那些需要重複輸入的部分,讓操作簡化。
:let @a="listdata["name"][""
:let @b=""]"
然後利用 normal 命令來直接運行操作,而不是直接執行寄存器(注意,vim 中的「宏」就是對記錄在寄存器中的按鍵的執行,所以你可以直接編寫宏,或者把宏用到其他命令中,宏只是寄存器的一種應用。)
:%norm yw$"ap"0p"bp
這種方式比使用宏好的地方在於,你不需要知道應該執行多少次宏,[range] 對於 normal 命令也適用,這個命令會自動從第一行執行到行末。
儘管你可以看到性能比之前有來明顯的提升,但是明顯還是比使用 %s 要慢,因此,在通常情況下,使用替換都會是更好的選擇。
那麼,在不能用正則表達式的情況下,我們真的就無法使用 substitute 了嗎?
當然不是,我這裡還有一個解決方案——利用 global! 命令調用 substitute ,你可以得到和 %s 接近的執行速度。
在本題中,使用 substitute 的難點在於:- 不能使用正則表達式所以無法構造 {pattern}
- 由於無法構造 {pattern} ,所以 substitute 無法使用,global 也無法直接使用
- execute 命令只能針對當前行,無法使用 [range] ,所以無法通過 execute 調用 substitue 配合 getline() 繞過正則表達式
- 使用任意一個不在文檔中的字元(我這裡使用了「+」)作為 {pattern} ,利用 global! 反向匹配到所有行
- 使用 execute 命令調用 substitute ,這樣就能使用 getline() 函數獲取每一行的內容,而不需要用到正則表達式
:v/+/exe "s/".getline(".")."/=listdata["name"][""]"
這樣我們就能繞過正則表達式來使用 substitute ,得到比使用宏更快的處理速度。
最後的最後,拋開 vim 本身的方法,如果你的電腦上還裝有 Python,那麼你就可以通過 Python 來處理。注意,我這裡說的是並不是「寫一個 Python 腳本來處理」,而是「在 vim 中直接調用 Python 來處理」。
首先,確保你的 vim 打開了 Python 介面支持
:version "看到 +python
:echo(has("python")) "返回 1
然後直接在命令欄中寫
py for i in range(len(vim.current.buffer)):vim.current.buffer[i]=vim.current.buffer[i]+"=listdata["name"][""+vim.current.buffer[i]+""]"
文本替換什麼的太低端,一句`:"&<,"&>s/(w*)/1=listdata["name"]["1"]/g`就搞定了會不會太無聊?
我來點不一樣的吧 ^_^
在文本前後輸入一些代碼使看起來這樣:
s = """
apple
bird
cat
dog
"""
print "
".join(x+"=listdata["name"][""+x+""]" for x in s.split("
") if x)
然後,選中所有這些文本,然後按下`!python`,回車即可見到效果。
以上是用python舉例,用其它腳本同理。
PS:這裡只是說怎麼解決題主的問題,當然實際情況下我從不會這麼干,我寧可在代碼里用eval。。。用宏!
1. 滑鼠放在第一行
2. 0yiw3. A=listdata["name"]["4. Esc p5.A"]apple=listdata["name"]["apple"]
bird=listdata["name"]["bird"]cat=listdata["name"]["cat"]dog=listdata["name"]["dog"]
與@李繼剛 的回答一致,這裡再補充說明一下。
使用「Record and playback commands」,用q啟用寄存功能,然後對第一行進行修改,這時修改記錄在寄存器內。最後對剩下幾行用寄存器裡面的記錄進行同樣的修改。
1. 游標在第一行的任意位置,點擊qa,開始記錄操作;
2. 0yiw (將游標置於行首,複製單詞);
3. A=listdata["name"][" (在行尾追加=listdata["name"][");
4. Esc p (回到normal模式,粘貼2中複製的單詞);
5. A"](在行尾追加"]);
6. Esc j(回到normal模式,將游標移動到下一行);
7. q(停止記錄);
8. 3@a(調用記錄的操作3次)
參考:Vim的user-manual中「Making big changes」一節。
用word的郵件合併(逃→_→)
方法挺多的。推薦一個插件:Multi-cursor.
Multi-cursor操作:
- shift +v選中要操作的內容
- CTRL + n: 使用Multi-cursor插件
- I:行首插入
- 繼續1,2兩部操作
- A: 行末插入
- ctrl + v :進入Visual Block模式,選中需要操作的內容
- I:在行首輸入入 並輸入要name=listdir["name"]["
- ctrl + v:進入 visual Block,選中整塊內容
- A: 行末輸入"]
拖拽至此處上傳
術業有專攻,請用awk sed
用正則表達式!
推薦閱讀: