歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網

神奇的VIM

日期:2017/2/27 9:43:38   编辑:更多Linux
  當今世界,文本編輯器種類繁多,大有"亂花漸欲迷人眼"之勢。中國有句古語:手巧不如家什妙,作為IT業的專業人士,選擇一款優秀的編輯軟件至關重要。筆者認為:Linux下的VIM※以其強大的功能和無窮的魅力將使您終生受益。 由於被廣泛移植,無論是PC機的DOS和WINDOWS,還是RISC/6000的AIX,乃至於IBM的大型機S/390,都能見到VIM的身影。然而,對於初學者,VIM的用戶界面與使用方法非常不符合常規,甚至認為它比較混亂,無所適從。事實上,VIM編輯器是專門為經驗豐富的用戶設計的,它的界面和使用方法提供了更快的速度和更強的功能。對於熟知它的用戶,VIM的許多特性節省了時間和擊鍵次數,並可以完成一些其他編輯器無法完成的功能。 學習的最好方法是實踐,唯有如此,才能真正掌握其中的精髓。文中列舉的實例,都是筆者在實際工作中遇到的,具有一定的代表性,請大家在閱讀的過程中仔細體會。 好了,現在讓我們共同暢游神奇的VIM的世界! 例一、兩個常用的指令序列 XP 左右交換光標處兩字符的位置。 ddp 上下交換光標處兩行的位置。 例二、重復輸入同一字符 有時,我們可能想多次輸入同一字符,VIM的插入功能可以很好的完成這項工作 命令 80i=^ESC 一次可以輸入80個字符= ,當然,80a=^ESC 也可以完成上述功能。 請注意:此處的^ESC表示鍵盤左上方上的ESC鍵。 例三、將兩個文本數據文件按行逐條合並,並給出標尺 數據文件1內容如下: 1----- 2----- 3----- 數據文件2內容如下: 1===== 2===== 3===== 要求的結果如下: --------1---------2---------3---------4---------5 1----- 1===== --------1---------2---------3---------4---------5 2----- 2===== --------1---------2---------3---------4---------5 3----- 3===== 也許您會說,這還不簡單,無非是反復拷貝、粘貼,任何一款文本編輯器都能完成上述功能。可是,如果這兩個文件都很大,每個文件都成千上萬行,恐怕簡單的拷貝、粘貼就難以勝任了。因此,我們所關心的,是找到一種行之有效的方法,把枯燥乏味的工作留給計算機,我們只需發布指令。為達到此目的,請按以下步驟執行: ㈠、將兩文件合並,結缦?1----- 2----- 3----- 1===== 2===== 3===== ㈡、在兩文件頭尾相接的地方插入標志行,用以區分兩個文件,本文采用的是一整行!字符 1----- 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! 1===== 2===== 3===== ㈢、在標志行的下方輸入標尺 1----- 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 1===== 2===== 3===== ㈣、執行宏命令腳本merge_2r.vim,即在VIM編輯器中按如下鍵 :so merge_2r.vim 回車 ㈤、按下鍵盤上的=鍵,執行的結果如下 --------1---------2---------3---------4---------5 1----- 1===== --------1---------2---------3---------4---------5 2----- 2===== --------1---------2---------3---------4---------5 3----- 3===== --------1---------2---------3---------4---------5 !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 ㈥、將最後三行刪除,即可得到我們需要的結果 --------1---------2---------3---------4---------5 1----- 1===== --------1---------2---------3---------4---------5 2----- 2===== --------1---------2---------3---------4---------5 3----- 3===== 怎麼樣,簡單嗎?請大家自己實際嘗試一下。下面,我來詳細講解宏命令腳本merge_2r.vim 。 該腳本內容如下: "-------------------------------------------------------------------- "Macro Function : Merge File1 And File2,Have Ruler in every record " Date : 2001/12/01 " Author : Yan Shi "-------------------------------------------------------------------- "1----- "2----- } Sample File1 "3----- "!!!!!!!!!!!!!!!!!!!!!!!! Flag Row "--------1---------2---------3---------4---------5 Ruler "1===== "2===== } Sample File2 "3===== "-------------------------------------------------------------------- :1 :map = ma/!!!!!^M+:.co 'a-1^M/!!!!!^M2+:.m'a^M+= 前14行每行都以"開始,表明該行是注釋行,實際並不執行,只是方便讀者閱讀,只有最後兩行才是真正的代碼行。請注意:本例中的^M表示鍵盤上的回車鍵,並非^和M兩個字符。為了講述清楚,我把命令行分解開,逐一說明。 首先將第一行置為當前行,然後執行map命令,將一大串VIM指令映像給字符=。這一大串VIM指令共分9步執行: ma 將數據文件一的第一行標記為a 1----- 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 1===== 2===== 3===== /!!!!!^M 找到標志行,置為當前行 1----- 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 1===== 2===== 3===== + 光標下移一行,即把標尺行置為當前行 1----- 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 1===== 2===== 3===== :.co 'a-1^M 把標尺行復制到標記行(數據文件一的第一行)的上方 --------1---------2---------3---------4---------5 1----- 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 1===== 2===== 3===== /!!!!!^M 再次找到標志行,置為當前行 --------1---------2---------3---------4---------5 1----- 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 1===== 2===== 3===== 2+ 光標下移2行,即數據文件二的第一行置為當前行 --------1---------2---------3---------4---------5 1----- 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 1===== 2===== 3===== :.m'a^M 把數據文件二的第一行移至標記行的下方 --------1---------2---------3---------4---------5 1----- 1===== 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 2===== 3===== + 光標下移一行,即數據文件一的第二行置為當前行 --------1---------2---------3---------4---------5 1----- 1===== 2----- 3----- !!!!!!!!!!!!!!!!!!!!!!!! --------1---------2---------3---------4---------5 2===== 3===== = 這一步很關鍵,是典型的遞歸調用,重復完成以上步驟 例四、在文件中置入行號 工作中,我們有時希望把行號置入文件中,而VIM提供的功能 :set nu 只能顯示行號,不能編輯或將其置入文件當中,下面的宏命令腳本row_num.vim可以完成此項功能。 "------------------------------------------ "Macro Function : Source File Add Row_Num " Date : 2001/12/01 " Author : Yan Shi "------------------------------------------ :%s/^/^I/ :$ :let end=line(".") :1 "------------------------------------------ :let num=1 :while num<=end :let line=getline(".") :let temp=substitute(line,$,num,"") :call setline(".",temp) :+ :let num=num+1 :endwhile "------------------------------------------ 請注意:本例中的^I表示鍵盤上的TAB鍵,並非^和I兩個字符。下面,我針對該宏命令腳本逐一講解。 :%s/^/^I/ 每一行的行首添加一個TAB字符 :$ 到文件的末行 :let end=line(".") 末行的行號 ==〉變量 END,函數line的功能是取得指定行的行號,此處參數"."表示當前行 :1 到文件的首行 "------------------------------------------ :let num=1 1 ==〉計數器 :while num<=end :let line=getline(".") 取當前行的內容 ==〉變量 LINE :let line=substitute(line,$,num,"") 在變量 LINE 的前面置入行號 :call setline(".",line) 將變量 LINE 的內容寫回當前行 :+ 下移一行 :let num=num+1 計數器加一 :endwhile 循環執行,直到文件結束 "------------------------------------------ 有關正則表達式的使用 UNIX/LINUX下的很多工具之所以強大、靈活,關鍵是因為有了正則文法和元字符,這也是VIM乃至UNIX/LINUX系統的精華所在。正因為使用靈活,因此掌握起來比較吃力,如果不是真正理解,實際運用中會出現千奇百怪的錯誤。因此,有必要對這部分知識多花些氣力。下面結合具體實例講解。 例五、有一文件,包含某外企的中國員工的資料,首先是姓名,然後是兩個空格,其次是15位身份證號碼。 zhang.fei 430759701022003 diao.chan 651302801225012 guan.yu 342869680413001 xi.shi 120638780214006 liu.bei 210324650708001 現在,有以下問題需要解決: 按照外國人的習慣,應該是名在前,姓在後。因此,文件中的姓名字段需要修改。 姓與名的首字母應該大寫。 根據身份證號碼,還可以判斷出生年月日,將其作為一個新字段添加。 根據身份證號碼,可以判斷出性別。若為男性,添加male,若為女性,添加female 。 將男女員工分開,男員工在前,女員工在後。 將各字段數據左對齊 最終結果如下: Fei.Zhang 430759701022003 1970/10/22 male Yu.Guan 342869680413001 1968/04/13 male Bei.Liu 210324650708001 1965/07/08 male ----------------------------------------------- Chan.Diao 651302801225012 1980/12/25 female Shi.Xi 120638780214006 1978/02/14 female 為了完成上述功能,只需執行腳本employee.vim ,使用方法為 :so employee.vim 回車即可。 腳本內容如下: :%s/ / / :%s/\(............\)\( *\)/\1/ :%s/\([A-Za-z][A-Za-z]*\)\(\.\)\([A-Za-z][A-Za-z]*\)/\u\3\2\u\1/ :%s/$/ xxxxxx/ :%s/\([0-9]\{6}\)\([0-9]\{6}\)\([0-9]\{3}\) \(xxxxxx\)/\1\2\3 \2/ :%s/\(..\)\(..\)\(..\)$/19\1\/\2\/\3 :%s/$/ xxxxxx/ :%s/\([0-9]\{14}[13579]\)\(.*\)\(xxxxxx\)/\1\2male / :%s/\([0-9]\{14}[02468]\)\(.*\)\(xxxxxx\)/\1\2female/ :$ :s/.*/&^M----------------------------------------------- :g/female/.m$ 在這個腳本中,使用了大量的正則表達式,這裡僅對涉及到的正則表達式做一簡要介紹。有關正則表達式的內容相當多,本文不可能占用大量篇幅敘述,請大家諒解。 % 地址范圍符號,代表文件中的所有行,作用等同於地址范圍 1,$ . 與任意單字符(換行符除外)匹配,例如 y.s 可以匹配 yas y.s 或 y s 等等。 * 與前一字符的0次或多次出現匹配,例如 y*s 可以匹配 yys yyyyys 或 s 等等。 $ 與行尾匹配。 & 代表模式匹配中出現的字符串,例如 s/abc/&def 是把當前行的abc替換成abcdef 。 [] 匹配[]中出現的字符,例如[abc]匹配字符 a,b 或 c ,[a-zA-Z]匹配所有的英文字符。 \( \) \(和\)之間出現的內容可以由\num來替代。 \1\2\3 替代\(和\)之間出現的內容。 \u 將後續字符串的首字母大寫。 \{num} 與前一字符的num次出現匹配。 現在,我們對腳本逐條講解,希望能幫助大家理解正則文法。 ⑴:%s/ / / 將文件中每行出現的2個空格替換為10個空格。 zhang.fei 430759701022003 diao.chan 651302801225012 guan.yu 342869680413001 xi.shi 120638780214006 liu.bei 210324650708001 ⑵:%s/\(............\)\( *\)/\1/ 保留行首的12個字符,將其余的空格刪除,這樣,前兩個字段就對齊了。 zhang.fei 430759701022003 diao.chan 651302801225012 guan.yu 342869680413001 xi.shi 120638780214006 liu.bei 210324650708001 ⑶:%s/\([A-Za-z][A-Za-z]*\)\(\.\)\([A-Za-z][A-Za-z]*\)/\u\3\2\u\1/ 將文件中每行出現的雇員姓名互換,並將首字母大寫。 Fei.Zhang 430759701022003 Chan.Diao 651302801225012 Yu.Guan 342869680413001 Shi.Xi 120638780214006 Bei.Liu 210324650708001 ⑷:%s/$/ xxxxxx/ 在每一行的行尾添加2個空格和6個x Fei.Zhang 430759701022003 xxxxxx Chan.Diao 651302801225012 xxxxxx Yu.Guan 342869680413001 xxxxxx Shi.Xi 120638780214006 xxxxxx Bei.Liu 210324650708001 xxxxxx ⑸:%s/\([0-9]\{6}\)\([0-9]\{6}\)\([0-9]\{3}\) \(xxxxxx\)/\1\2\3 \2/ 將xxxxxx替換成出生年月日。 Fei.Zhang 430759701022003 701022 Chan.Diao 651302801225012 801225 Yu.Guan 342869680413001 680413 Shi.Xi 120638780214006 780214 Bei.Liu 210324650708001 650708 ⑹:%s/\(..\)\(..\)\(..\)$/19\1\/\2\/\3 將年月日用/字符分隔,並在年前添加19。 Fei.Zhang 430759701022003 1970/10/22 Chan.Diao 651302801225012 1980/12/25 Yu.Guan 342869680413001 1968/04/13 Shi.Xi 120638780214006 1978/02/14 Bei.Liu 210324650708001 1965/07/08 ⑺:%s/$/ xxxxxx/ 在每一行的行尾添加2個空格和6個x Fei.Zhang 430759701022003 1970/10/22 xxxxxx Chan.Diao 651302801225012 1980/12/25 xxxxxx Yu.Guan 342869680413001 1968/04/13 xxxxxx Shi.Xi 120638780214006 1978/02/14 xxxxxx Bei.Liu 210324650708001 1965/07/08 xxxxxx ⑻:%s/\([0-9]\{14}[13579]\)\(.*\)\(xxxxxx\)/\1\2male / 身份證號碼末位是奇數的,將xxxxxx替換成male Fei.Zhang 430759701022003 1970/10/22 male Chan.Diao 651302801225012 1980/12/25 xxxxxx Yu.Guan 342869680413001 1968/04/13 male Shi.Xi 120638780214006 1978/02/14 xxxxxx Bei.Liu 210324650708001 1965/07/08 male ⑼:%s/\([0-9]\{14}[02468]\)\(.*\)\(xxxxxx\)/\1\2female/ 身份證號碼末位是偶數的,將xxxxxx替換成female Fei.Zhang 430759701022003 1970/10/22 male Chan.Diao 651302801225012 1980/12/25 female Yu.Guan 342869680413001 1968/04/13 male Shi.Xi 120638780214006 1978/02/14 female Bei.Liu 210324650708001 1965/07/08 male ⑽:$ 到文件的最後一行 ⑾:s/.*/&^M----------------------------------------------- 在文件的最末行插入一行 "-" 字符。 Fei.Zhang 430759701022003 1970/10/22 male Chan.Diao 651302801225012 1980/12/25 female Yu.Guan 342869680413001 1968/04/13 male Shi.Xi 120638780214006 1978/02/14 female Bei.Liu 210324650708001 1965/07/08 male ----------------------------------------------- ⑿:g/female/.m$ 將所有的女員工記錄移至文件尾。 Fei.Zhang 430759701022003 1970/10/22 male Yu.Guan 342869680413001 1968/04/13 male Bei.Liu 210324650708001 1965/07/08 male ----------------------------------------------- Chan.Diao 651302801225012 1980/12/25 female Shi.Xi 120638780214006 1978/02/14 female 筆者目前正在為某外資公司從事大型機(IBM S/390)的軟件開發,一切工作都在TSO環境中進行。為了對編寫的程序進行測試,必須准備測試數據。有過大型機開發經驗的人會知道,通過TSO,輸入字符型數據還可以,如果要輸入16進制數據,操作起來很麻煩。因為16進制數是縱向排列的,輸入時既不方便,又很容易錯位。怎麼解決呢?我嘗試了幾種辦法,實際證明,用VIM最方便。 例六、下列數據 1234567890ABCDEF ,將其變成 13579ACE 24680BDF 的形式,這樣,數據就可以很方便的粘貼到TSO環境中了。 下面給出宏命令腳本change_d.vim "---------------------------------------------------- "Macro Function : Convert Char Arrange Direction " " Sample : 40 50 60 ==> 4 5 6 " 0 0 0 " Date : 2001/12/01 " Author : Yan Shi "---------------------------------------------------- :s/.*/&^M/ :1 :map = malx+$p-`al= 說明如下: ⑴ :s/.*/&^M/ 在數據行下方添加一空行。 ⑵ :1 回到文件的首行的首字符。 ⑶ :map = malx+$p-`al= 將一大串VIM命令映像給字符= ① ma 將首字符標記為a ② l 光標右移一個字符 ③ x 刪除光標處字符 ④ + 移至下一行 ⑤ $ 到行尾 ⑥ p 將刪除的字符粘貼 ⑦ - 回至上一行 ⑧ `a 返回到標記字符處 ⑨ l 光標右移一個字符 ⑩ = 遞歸調用,重復以上步驟,直到將該行所有的數據處理完。 上面的這幾個實例,展示了VIM強大的文本處理功能,但這遠不能覆蓋其全貌。VIM的命令很多,而且使用靈活,需要狠下一番氣力才能熟練掌握。筆者年齡尚小,經驗還很欠缺,希望本文能夠起到拋磚引玉的作用。由於時間的原因,上述實例僅在DOS和WINDOWS環境下測試,沒有在其他系統下進行進一步的測試,希望各位同行、前輩不吝賜教,謝謝! ※ VIM 意為 VI Improved ,與VI99%向下兼容。而且,VIM提供了許多VI不具備的功能,內置了諸多函數,因此,建議有經驗的VI用戶對VIM有所了解,您會發現,轉向VIM是明智之舉。欲查詢有關VIM的資料,請參考 http://www.vim.org 注:本文使用 VIM 6.0 版本 作者簡介 闫石,工程師。您可以通過電子郵件:[email protected] 或者 [email protected] 和他聯系。




Copyright © Linux教程網 All Rights Reserved