大家來學VIM(一個歷久彌新的編輯器)[十]
|
基本的匹配 |
* 指前所綁住的字元或字元集合,出現 0 次或 0 次以上。 \+ 和 * 作用相同,但不包括出現 0 次。 \= 指前所綁住的字元恰好出現 0 或 1 次。 \| 這是多選,就是 or 的意思,被 \| 隔開的 pattern,任一個符 合的話就算符合。
[實例] dg* 指 * 前所綁住的字元 g 出現 0 次或 0 次以上。也就是說 d(出現 0 次),dg,dgggg,dgggggggg 都是符合這個 pattern。如果您下尋找指令 /dg*,那符合這個 pattern 的字串都會被找出來。如果用在代換就要非常小心了,像 extended 中的 d 也是會被置換掉的。例如您下 :%s/dg*/test/g 的話,那 extended 這個字會換成 extentestetest。 |
[實例] dg\+ dg, dgg, dgggggg 皆符合,但 d 則不符合。如果是 dg\= 的話,就只有 d、dg 這兩個符合了。 |
[實例] :%s/The\|All/test/g 全文中只要是 The 或 All 都會被替換成 test。注意,如果文中有 There 也是會被替換成 testre!要如何避免這種情形呢?下面會另述及限定使用法。 |
[實例] /123-\=4567 這樣會找出,123-4567 及 1234567。當然 123-456789 也是會被找出來。 |
[...] 字元集合,表示中括號中所有字元中的其中一個。 [^..] 這是上述 [...] 的補集,表非中括號內字元的其中一個。 . 除換行字元外的任一單一字元。指本身,非指前所綁之字元。 就好像 shell 中的 ? 一樣。如果要指定真正的英文句點,要 用 \ 來 escape,就是說 \. 這時的 . 是代表真正句點,而不 是 regexp 中的特殊意義。其他如 \* 亦同。
[實例]
|
[實例] W[0-9]*\.cc 這個例子是說以 W 開頭,後接 0-9 其中一個或多個數目字或不接什麼,然後是一個句點,最後是 cc。所以 W.cc,W1.cc,W2.cc,W345.cc,W8976543287.cc 皆符合。如果要表示 W 及 .cc 間夾一個以上的數目字,要寫成 W[0-9][0-9]*\.cc。 |
[實例] .* 這代表任意字元或字串,或什麼都沒有,腦筋急轉彎,對照前面的定義想一下。當然這是不包括換行字元的。 |
[實例] [^M] 表除 M 以外的任意字元。 [^Tt] 表 T 及 t 以外的任意字元。 [^0-9] 表非數目字之字元。 [^a-zA-Z] 表非英文字母之字元。 |
^ 匹配行首,指其後綁住的字串,出現在行首才符合。 $ 匹配行尾,指其前綁住的字串,出現在行尾才符合。含換行字元。
[實例] /^What 這樣只有在行首的 What 才會被找出來。注意! Whatever, What's 也是會被找出來。如果是 /What$ 則是在行尾的 What 才會被找出來。 |
[實例] ^$ 這是什麼東東?行首也是行尾的行。ㄚ,就是空白行嘛!當然也不能說這個行是沒有什麼東東啦!空白行至少也是會有個換行字元。在後面會詳述如何消除全文的空白行。 |
\(...\) 記憶 pattern,可由 \1, \2...\9 來叫出。
[實例] :%s/\([a-z]\)\1/test/g 這樣 aa, bb, cc, dd, ..., zz 都會被 test 替換掉。這和 :%s/[a-z][a-z]/test/g 是不一樣的意思,後者會把 aa, ab, ac... ba, bb, bc...zz 都換成 test。也就是說 \(...\) 由 \1 叫出時會有對稱性的配對出現。 |
[實例] :%s/\(.\)\(.\)r\2\1/test/g 會將中間為 r,前有二個任一字元,後有兩個具對稱性的字元所組成的字串替換成 test。\2 是呼叫第二組 \(.\),而 \1 是呼叫第一組 \(.\)。例如:12r21,cfrfc,7grg7 等都會被替換成 test。 |
\< 匹配字(word)首。所謂 word 包括文數字及底線。 \> 匹配字尾。這就是前所提及的限定用法,被 \<,或 \> 括住的 pattern 就會被限制住,使 regexp 不能再向右(左)擴充解釋。
[實例] :%s/\<abbbc\>/test/g 這樣只有 abbbc 才會被替換成 test。如果沒有這樣限定,:%s/abbbc/test/g,那 deabbbcly 中的 "abbbc" 亦會被替換成 test。所以前面 :%s/The\|All/test/g 可換成 :%s/\<The\>\|\<All\>/test/g 這樣一來,There 就不會被替換成 testre 了! |
[實例] :%s/\<abbbc/test/g 這樣的話,只要是以 abbbc 為首的字(word),其中的 abbbc 的部份都會被 test 所替換。注意!是指字首,而不是指行首。所以 abbbc,abbbcerd,abbbckijuds 都符合。 |
\{n,m} 指前所綁住的字元或字元集合最少出現 n 次,最多出現 m 次。
[實例] \{最小值,最大值} 如 [0-9]\{3,4} 匹配至少三位數,但不可多於四位數的數目字。如: 123 12 1 123456 1234567 12345678 1234 12345如果下 :%s/[0-9]\{3,4}/test/g 的話,那 1,12 這兩組不會被替換,因為不滿 3 位數。而 12345,則會換成 test5。123456,則會換成 test56。12345678,則會換成 testtest。1234567 也是會換成 testtest。123,1234 這兩組則會被替換成 test。您可以親自操作一次就知道怎麼一回事了。操作時最後加 gc 來 confirm,這樣您會更瞭解實際替換的內容。ㄟ,別忘了 u 可以回複您的編輯動作。 |
[實例] \{數目字} xy\{20} 表示 x 後接 20 個 y。 e[x-z]\{4} 表示 e 後接有四個字元,是 x,y,z 的其中一個的 組合。如:exxxx, exyyz, ezzyz, exyzz 皆符合。 |
[實例] \{最小值,} xy\{2,} 表 x 後接至少二個的 y。相當於 xyyy* 或 xyy\+ 。 |
[實例] \{,最大值} xy\{,4} 表 x 後接至多四個或更少的 y (可能沒有)。 因此 x, xy, xyy ,xyyy, xyyyy 皆符合。 |
中介字元(metacharacter, or character classes) |
主要是簡化 regexp 的書寫。
\s 表空白字元,即 <Space> 或 <Tab>。
\S 表非空白字元。 \d 表數目字(digits),即 [0-9]。 \D 表非數目字,即 [^0-9]。 \w 表一般字元(word character),包括底線。即 [0-9a-zA-Z_]。 \W 表非一般字元,即 [^0-9a-zA-Z_]。 \a 表英文字母(alphabetic character),即 [a-zA-Z]。 \A 表非英文字母,即 [^a-zA-Z]。 \l 表小寫字母(lowercase character),即 [a-z]。 \L 表非小寫字母,即 [^a-z]。 \u 表大寫字母(uppercase),即 [A-Z]。 \U 表非大寫字母,即 [^A-Z]。
全域性的指令 |
:[range]g/pattern/[cmd]cmd 是 ed 可用的指令,預設是 p(print),您可查一下 man ed,就可以知道有什麼指令可用。這個小節裡主要是說明 d(delete) 的功能。因為是要說明如何消除空白行。需注意的是,d 是行刪除指令,凡含 pattern 的整行都會被刪掉,而且 range 不指定的話,預設是全篇文章,因為 g 就是代表 globe。
:g/^$/d這樣就會刪除全文的空白行。前面已提過 ^$ 代表的是空白行。但這裡有個問題,如果空白行裡包含了其它空白字元(即 Space 或 Tab)的話。表面看起來是和一般空白行一模一樣,但卻暗藏玄機,用上面的方法就無法刪除這種空白行了!怎麼辦?來!看招!
:g/^[<Space><Tab>]*$/d在 vim 或 elvis 裡您可以如此照打,也就是 <Space> 代表空白字元,<Tab> 代表按 Tab 鍵的結果。在原始 vi 則不行,得自行按出特殊字元出來,就是 Ctrl-v Space 及 Ctrl-v Tab。或採更簡單的打法:
:g/^\s*$/d還記得中介中元嗎?好用吧!少打了不少字。:-) 意思就是刪除含 0 或 1 個以上空白字元的行。
有些書中寫成 :%s/^$//g 可以刪除空白行,這是錯誤的,因為 :s 這 個指令只更動一行裡的內容物,但不會做刪除一行的動作。
& 替代變數 |
代表置換時合於 patern 的字元或字串。
[實例] :%s/\u\d\d\d\d\d\d\d\d\d\>/ID:&/g 這樣全文中的身份證字號前就會加上 ID: 字樣,也就是說 T123456789 會被換成 ID:T123456789。還記得嗎? \d 就是 [0-9],\u 代表大寫的英文字母。加個 \> 是防止 T12345678999 也被換掉。當然前面再加個 \< 更保險。ID: 字樣您用中文也行! 另一個好用的例子是電話號碼前加上 TeL:,就請您自行練習了! |
[實例] 將檔案 3 至 7 行的資料向右移 2 個空白:3,7s/.*/ &/但這樣連空白行也是會插入空白字元,較高明的做法是: :3,7s/.\+/ &/這樣空白行就不會去動它了!想通了 .* 及 .\+ 的意思了嗎?往前翻一下 . * \+ 的定義。 |
[實例] 將檔案 3 至 7 行的資料向左移 2 個空白:3,7s/^ //就是刪去行首的二個空白啦! |
[實例] 將全文的 Edward 這個單字,前後加上中括號:%s/\<Edward\>/[&]/g |
[實例] 將全文的 Edward 這個單字,改成大寫的。:%s/\<Edward\>/\U&/g |
[實例] 將全文每行最後加上 <BR> 這個 HTML tag。:%s/.*/&<BR>/g |
怎麼樣,是否已感覺到 regexp 威力無窮了呢?還是您已經快睡著了呢?:-) 不過也請您想想,如果是在沒有 regexp 功能的編輯器裡,範例中的一些動作您會怎麼做呢?一個一個去改?
greedy 陷阱 |
regexp 會有貪心的傾向,什麼意思呢?就是說在同一行內,如果有多個符合 pattern 的情形,會找最長的那一個。
[實例] This is a test. Test for regexp. 如果您下 :%s/[Tt].*t/program/g 原意是想把所有的 Test 或 test 換成 program 的,結果由於 regexp 的貪心,整個 "This is a test. Test" 會換成 program。結果原文就變成了 program for regexp. 因此在全文替換時要非常小心,避免使用彈性太大的 regexp。像此例,只要下 :%s/\<[Tt]est\>/program/g 就可以了! |
最後提醒您,這可不是 regexp 的全部,礙於篇幅及在下功力的問題,當然是沒辦法全面詳盡的向各位做介紹,在下只是將各位領進門,修行就得看各位了!如果還想更深入的研究 regexp,可參考: Mastering Regular Expressions(O'Reilly & Associates) 一書。
前單元 | 目 錄 |