Vim技巧 – 替換的巧妙使用

來源:互聯網
上載者:User
如何將一串十進位數字轉換為16進位數字,使用VIM完成轉換的最簡單方法如下:
:%s/\d\+/\=printf("%X", submatch(0))/g

這條命令的原理是,把一串數字,用printf()函數的輸出替換掉,printf()函數輸出的正是這串數位16進位形式。

分解如下:
%s 在整個檔案中替換 (:help :s )
\d\+ 匹配一個或多個數字 (:help /\d :help /\+ )
\= 使用運算式的結果進行替換 (:help /\w )
printf 按指定格式輸出 (:help printf() )
submatch() 返回:s命令中的指定匹配字串 (:help submatch() )
g 替換行內所有出現的匹配 (:help :s_flags)

看來,替換命令的巧妙使用可以完成很多意想不到的功能!

下面這個技巧是在VIM郵件清單中看到的,非常實用。

這裡以編寫C語言程式為例, 假設,我們最終想完成的代碼如下:
#define BIT_MASK_1 (1 << 0)
#define BIT_MASK_2 (1 << 1)
#define BIT_MASK_3 (1 << 2)
#define BIT_MASK_4 (1 << 3)
#define BIT_MASK_5 (1 << 4)
#define BIT_MASK_6 (1 << 5)
#define BIT_MASK_7 (1 << 6)
#define BIT_MASK_8 (1 << 7)
#define BIT_MASK_9 (1 << 8)
#define BIT_MASK_10 (1 << 9)
#define BIT_MASK_11 (1 << 10)
#define BIT_MASK_12 (1 << 11)
#define BIT_MASK_13 (1 << 12)
#define BIT_MASK_14 (1 << 13)
#define BIT_MASK_15 (1 << 14)
#define BIT_MASK_16 (1 << 15)
#define BIT_MASK_17 (1 << 16)
#define BIT_MASK_18 (1 << 17)
#define BIT_MASK_19 (1 << 18)
#define BIT_MASK_20 (1 << 19)
#define BIT_MASK_21 (1 << 20)
#define BIT_MASK_22 (1 << 21)
#define BIT_MASK_23 (1 << 22)
#define BIT_MASK_24 (1 << 23)
#define BIT_MASK_25 (1 << 24)
#define BIT_MASK_26 (1 << 25)
#define BIT_MASK_27 (1 << 26)
#define BIT_MASK_28 (1 << 27)
#define BIT_MASK_29 (1 << 28)
#define BIT_MASK_30 (1 << 29)
#define BIT_MASK_31 (1 << 30)
#define BIT_MASK_32 (1 << 31)

我們不需要一行一行的去寫,只需要先寫好第一行,如下:
#define BIT_MASK_1 (1 << 0)

然後,我們回到Normal模式,在這一行上輸入"Y31p",拷貝此行,然後粘貼31次。這樣,我們得到總共32行上面的內容。
現在使用"V31j"命令選中這32行,然後使用兩次替換命令:
:'<,'>s/BIT_MASK_\zs\d*\ze/\=line(".") - line("'<") + 1
:'<,'>s/\zs\d*\ze)$/\=line(".")-line("'<")

這樣,我們就得到了我們想要的結果。
這種方式還可以用於數組下標的自動增加,以及文本的章節自動編號等功能。只要你能夠用Regex準確的定位出你想要自動編號的的數字,那麼就可以使用這種方法來自動編號。

以第一條命令為例,第二條命令和第一條命令類似:

:'<,'>s/BIT_MASK_\zs\d*\ze/\=line(".") - line("'<") + 1

這條命令在我們選中的地區內進行替換,尋找以"BIT_MASK_"開頭,後面跟任意多個數位字串,並把匹配位置放在數字上,然後使用後面運算式計算出來的數字替換這些匹配的數字。
下面是這條命令中每個元素的含義:
'<,'> 我們所選中的地區 (:help '<,:help '> )
s 在選中的地區中進行替換 (:help :s )
\zs 指明匹配由此開始 (:help /\zs )
\d* 尋找任意位元的數字 (:help /\d )
\ze 指明匹配到此為止 (:help /\ze )
\= 指明後面是一個運算式 (:help :s\= )
line(".") 當前游標所在行的行號 (:help line() )
line("'<") 我們所選地區中第一行的行號 (:help line() )

"'<"和"'>"是我們使用了"v","V"命令選中一個visual地區後,VIM設定的標記,分別用來標識visual地區的開始和結束。
"BIT_MASK_\zs\d*\ze"是一個Regex,用來尋找以"BIT_MASK_"開頭,後面跟任意多個數位字串。其中"\zs"、"\ze"用來指定匹配的開始和結束位置,因為我們只打算替換"BIT_MASK_0"中的數字,所以在尋找時只把匹配地區置在數字上。
由於我們的替換操作要把不同行的數字替換成不同的值,所以在這裡需要使用一個運算式來計算出替換後的值。當":s"命令的替換字串是以"\="開頭時,表明使用一個運算式計算的結果進行替換。我們這裡的運算式就是"line(".")
- line("'<") +
1",其中"line()"函數用來獲得行號,它可以獲得當前行的行號,以及指定的標記(mark)所在的行號。"line(".")"用來獲得當前游標所在行的行號,"line("'<")"則用來獲得"'<"標記所在行的行號。這兩個行號的差加上1就是我們想替換的值。

在上面的例子中,我們使用VIM的替換功能,實現高效的代碼編寫。現在介紹另外一種方法,實現相同的功能。

我們先看例子:
UniqueID2 = lview.focusedItem.subItems.opIndex(0).text;
Parent = lview.focusedItem.subItems.opIndex(0).text;
Children = lview.focusedItem.subItems.opIndex(0).text;
login = lview.focusedItem.subItems.opIndex(1).text;
txtCust.text = lview.focusedItem.subItems.opIndex(2).text;
txtProj.text = lview.focusedItem.subItems.opIndex(3).text;
txtbDate.text = lview.focusedItem.subItems.opIndex(4).text;
txtdDate.text = lview.focusedItem.subItems.opIndex(5).text;
txteDate.text = lview.focusedItem.subItems.opIndex(6).text;
txtPM.text = lview.focusedItem.subItems.opIndex(7).text;
txtLang.text = lview.focusedItem.subItems.opIndex(8).text;
txtVendor.text = lview.focusedItem.subItems.opIndex(9).text;
txtInvoice.text = lview.focusedItem.subItems.opIndex(10).text;
txtPMFund.text = lview.focusedItem.subItems.opIndex(11).text;
txtProjFund.text= lview.focusedItem.subItems.opIndex(12).text;
txtA_No.text = lview.focusedItem.subItems.opIndex(13).text;
txtNotes.text = lview.focusedItem.subItems.opIndex(14).text;
txtStatus.text = lview.focusedItem.subItems.opIndex(15).text;

我們要把上面代碼中括弧中的數字,替換成由0開始的一個順序遞增序列,例如:
UniqueID2 = lview.focusedItem.subItems.opIndex(0).text;
Parent = lview.focusedItem.subItems.opIndex(1).text;
Children = lview.focusedItem.subItems.opIndex(2).text;
……

實現以上需求,除了用前面介紹的方法外,還可以用下面的命令:
:let n=0 | g/opIndex(\zs\d\+/s//\=n/|let n+=1

這條命令同上一篇介紹的命令類似,它也使用了VIM的替換功能和運算式,不同之處在於它並不需要事先選中替換地區,因為它沒有使用"line()"函數來計算當前位置的位移,而是直接使用變數來進行賦值。
下面簡單講解一下這條命令各個組成元素:
let 為變數賦值 (:help let )
| 用來分隔不同的命令 (:help :bar )
g 在匹配後面模式的行中執行指定的ex命令 (:help :g )
\zs 指明匹配由此開始 (:help /\zs )
\d\+ 尋找1個或多個數字 (:help /\d )
s 對匹配模式進行替換 (:help :s )
\= 指明後面是一個運算式 (:help :s\= )

所以,這條命令的執行過程為:
1. 給變數n賦值為0;
2. 尋找模式" opIndex(\zs\d\+",使用變數n的值替換匹配的模式字串;
3. 給變數n加1;

需要說明一下"|",它用來分隔不同的命令。
另外,在substitute命令中,如果省略匹配模式字串,它會使用之前定義的匹配模式字串,在本例中就是由"global"命令定義的"opIndex(\zs\d\+"。

除了上面介紹的方法外,還有一個VIM外掛程式專門實現數字、日期等的增、減,可以在下面的網址下載此外掛程式:
http://vim.sourceforge.net/scripts/script.php?script_id=670

http://mysite.verizon.net/astronaut/vim/index.html#VISINCR

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.