专注各种脚本编程
Baidu
加入收藏夹
本站内容有下面分类知识,欢迎您的到来^_^
shell相关:指令篇 基础篇 脚本欣赏 编程实例 shell问问 shell视频教程 技巧篇 水平测试 E文资料 vi编辑器 高级Bash脚本编程指南
其他:mysql perl c语言 oracle
当前位置:| 主页>shell编辑器>

Vi- 全域代换

百度收藏 QQ搜藏
當你在編輯一份文件時,有時候可能會發現有一個名詞或單字必須被修改,這時候你可能必須要修改整個文件中出現這的名詞或單字的地方,這個時候你可以用全域代換來完成。

代換的指令是 s/pattern1/pattern2/,這個指令要在 line mode 使用。 Vi 會將 pattern1 取代為 pattern2Pattern 翻譯成中文是樣式,用 pattern 而不用 string﹝字串﹞的理由讀者很快會知道。

當你要代換文字時,你必須要先指定列數,當你下指令 1,$s/student/teacher/, vi 會把整份文件的 student 取代成 teacher。但是這樣還不夠,這個指令只會把每一列的第一個 student 取代成 teacher ,如果一列中有兩個 student 的話,那只有第一個 student 會被代換成 teacher。如果你是要把整份文件的 student 代換成 teacher,那你的指令應該是 1,$s/student/teacher/g。放在指令尾巴的 g 是全域﹝global﹞的意思,加上這個指令,不管你一列中出現幾次 student,全部會代換成 teacher。

當你在作全域代換時一定要小心,特別是只代換一個字的時候,常常會發現有些不想代換的字被代換。例如你下指令 1,$s/行/列/g,這個指令為把文章裡的「行」代換成「列」,所以「執行」會變成「執列」,這就不是我們想要的結果。為了小心起見,我們可以再加一個指令 c(confirm),這樣 vi 在每次代換之前就會先詢問是否要代換,所以上面的指令可以改成 1,$s/行/列/gc

 

Regular expression

現在把重點放到 pattern,也就是樣式。在前面有說過,vi 會把 patter1 代換成 pattern2。但是或許你會發現,有幾個符號會出現一些錯誤,這些符號大概有 .*^$\[] 等。這是因為 vi 對字串的搜尋是支援 regular expression 的。 Regular expression,翻譯作「規則字串」,是 unix 定下的一種規則。當你在搜尋字串時,只要依照 regular expression 告訴程式你要尋找的字串大概是什麼樣子,程式就會將符合條件的字串找出來。而上述的那些符號就是 regular expression 使用的符號,所以 vi 會用不同的意義解釋這些符號。

如果你希望 vi 用原來的意義解釋那些符號,只要在前面加上 \﹝跳脫字元﹞就行了。例如你要代換「\」成「*」,就下指令 1,$s/\\/*/g。在 pattern2 的 * 前面不加 \ 是因為 pattern2 不是搜尋用的,所以規則和 pattern1 不一樣。

現在我們了了解一下用在 regular expression 的符號代表什麼意義:

  • . 代表任意一個可見字符或空格或 tab。如果你的 vi 認得中文字,那 . 也代表任意一個中文字。比如指令 1,$s/a.b/ab/g,這個指令會把你文章中出現的字串像是 acb、a愛b 等代換成 ab。

    再比如指令 1,$s/././g,這個指令會把你文章中的每一個字元都換成「.」,在 pattern1 中的「.」是一個規則字串,代表任意一個字元。而在 pattern2 的「.」則代表字元「.」。很明顯地,如果在 pattern2 中 . 依然代表任何一個字元,那 vi 就無法知道要代入什麼字元了,總不能跟它說隨便啦。

     

  • * 的前面一定要有一個字元,如果沒有,那它就代表字元「*」。當一個字元後面跟著 * 時,表示那個字元重複出現從零到任意多﹝越多越好﹞次。例如下指令 1,$s/aa*/a/g會將如 a、aa、aaaaaaaa 這樣格式的字串代換成 a。

    pattern1 中使用 aa* 和 a* 結果是不同的,因為 a* 代表從任意多﹝越多越好﹞個 a,所以 1,$s/a*/a/g 會變成任兩個字元之間都會插入一個 a。之前有「越多越好」,這是指像 aaaaaaaaa 這樣的字串, a* 一定是代表 aaaaaaaaa,而不會代表 aa 或是 aaaa。

     

  • ^ 放在最前面就代表一列的開頭,否則就代表字元「^」。例如 1,$s/^Key/Lock/ 會把出現在開頭的 Key 換成 Lock,而不是在開頭的 Key 則不會有影響。這樣的指令我想是用不著加 g(global),因為一列大概只會有一個開頭。

     

  • $ 放在最後面就代表一列的尾巴,否則就代表字元「$」。例如 1,$s/Lock$/Key/ 會把出現在尾巴的 Lock 換成 Key,而不在尾巴的 Lock 不會有影響。

     

  • [] 是一對的,這兩個字元要同時使用。放在方括號內的所有字元只要找到一個就算是符合條件。舉個例子:.,20s/2[abcd]/2e/g 會將目前這一列到第二十列的 2a、 2b、2c、2d 代換成 2e。

    方括號中還有另一種指定法:[a-z] 表示從 a 到 z 中的任一字元。 [B-Ea-z3-5] 表示 B 到 E、a 到 z 和 3 到 5 中的任一字元。

    在方括號的開頭放入 ^ 表示否定。例如 5,100s/[^a-z]//g 會把第五列到第一百列中所有「不是」小寫英文字母的字元全部刪除。如果在方括號中 ^ 不是放在開頭的話,那它就表示字元「^」。

    在方括號中除了 \、-、] 和放在開頭的 ^,所有的符號如 *、. 等都代表原來的意義。如果要讓那四個符號表示原來的意義,只要在前面加上 \。 例如 [\^\\\-\]] 就代表 ^、\、-、] 中的任一字元。

     

  • 以上介紹的符號是可以混合使用的。

    例如下指令 1,$s/^...//g 會把每一列開頭的三個字元刪除。

    1,$s/ [a-z]* //g 則是把小寫的單字全刪除﹝pattern1 的開頭和結尾是空白字元﹞。

    1,$s/.*//g 則會把所有的列換成空列。

     

看到這裡,你會發現上面介紹的 regurlar expression 都是用在 pattern1,沒有一個能用在 pattern2。接下來要介紹的就是用在 pattern2 的語法。
  • & 代表 pattern1 所找到的字串。例如指令 s/ry*s/a&z/g 會把 rs 代換成 arsz, rys 代換 arysz,ryys 代換成 aryysz 等。在你想要把某種格式的字串的前面或後面再加上文字時用 & 會非常方便。 再比如 s/.*/mv & &.txt/,如果某一列是 foo,這個指令會把它變成 mv foo foo.txt。

     

  • ~ 會記錄你上一個使用的 pattern2。例如先下指令 s/his/their/g,再下指令 s/his/~/g,這時候第二個指令的 ~ 會變成 their。

     

  • \(\) 是成對的,包含在其間的「樣式」會被放到暫存區中。最多可以放到九個,vi 會依序自動編號,從 1 到 9。要使用暫存區只要按 \ 以後再按暫存區的編號。 \( 和 \) 其實還是用在 pattern1,但是我認為這個部分對 pattern2 較有意義,所以就放在這裡說明,請看下面的範例就可以明白。

    s/b\(.*\)k/k\1b/g 這個指令會把類似 bxxxxxxk 的字串代換成 kxxxxxxb。中間的 xxxxxx 不會改變。回頭看這個指令,夾在 \( 和 \) 之間的﹝要是不習慣,把 \ 當成隱形的,就只剩下 ( 和 ),這樣想會比較容易接受﹞的「樣式」是 .*,表示任何一個字串,越長越好。加上頭和尾,就是 b.*k。所以 vi 會搜尋到 bk、book、bank、basic practice is pk 等等的字串。每次搜尋到之後,vi 把中間的字串放入暫存區 1,然後我們在 pattern2 要求 vi 把暫存區 1 的字串拿來,頭跟尾加上其他字元,然後再代換原來的字串。

    再看一個例子,指令 1,$s/b\([aeiou]\)c\([sz]\)/r\1g\2/g,在 pattern2 的 \1 代表 [aeiou],\2 則代表 [sz],所以這個指令會把整份文件的 bacs 代換成 rags, bicz 代換成 rigz 等共有十種字串會被代換。

     

  • \u 會把後面的字元變成大寫, \l﹝這是小寫 L﹞會把後面的字元變成小寫。舉例來說,指令 s/rar/\uzi\lp/g 等於指令 s/rar/Zip/g。再說一個例子,有個句子 He and she are my friends.,你想要把 He 和 her 對調﹝宣示女男平等﹞,下指令 s/\(He\) and \(she\)/\u\2 and \l\1/g,句子就會變成 She and he are my friends.。你可以試試看上面的指令如果不用 \u\l 的話會有什麼結果。

     

  • \U 會把後面的字變成大寫,\L 會把後面的字變成小寫。如果後面沒有 \e\E,那 \U\L 會運作到結尾,否則會運作到 \e\E。例如指令 s/[a-z][a-z]*/\U&/g 會把所有的小寫單字變成大寫。再比如指令 s/\([Tt]he\) hunter/\U\1\e hunter/g,會把 The hunter 或 the hunter 代換成 THE hunter。

     

其他的指令

現在 regular expression 介紹到這裡,接著要再介紹一些跟代換有關的指令。

直接下指令 s 會重複上一個代換。例如先下指令 110s/a/b/g,再下指令 s,就等於指令 s/a/b/﹝注意,沒有 g﹞。

在 command mode 下按【 & 】就等於 line mode 下的 s,可以少按兩個按鍵。不過無法指令列數,也不能在後面加 g

在前面的代換指令中,尾巴大部分都跟著 g(global),其實 g 還有其他的用法。當你下指令 g/bgs 時,vi 會找到所有含有 bgs 的列,並且全部印出來。所以我們也可以下指令 g/bgs/d,含有 bgs 的列會全部被刪除。這是一種指定列數的方法,即使這些列不連續也會被 vi 接受。

用上述的方式,我們可以這樣下指令 g/bgs/s/heresy/shann/g,這個指令會找出所有包含 bgs 的列,然後把這些列的 heresy 換成 shann,其他不包含 bgs 的列的 heresy 則保持不動。

全域代換的基本指令大致介紹完畢,剩下的就是應用。這方面的組合可以說有無窮多,只要你自己覺得方便就行了。我沒提到的細節,就是重複上一個代換。我認為少打那幾個字差不了多少。如果要一列一列修改,那乾脆用 command mode 還比較快。

上一篇:Vi- Line mode 下一篇:Vi- 执行Shell 命令

power by soyo123 2007-2008