1.3 文本匹配
一些unix的文本處理程序讓你可以搜索,某些時候可以改變一些文本模式,而不是固定的字串。這些應用包括編輯工具ed,ex,vi和sed,還有awk程序語言和命令行命令grep和egrep.文本模式(更正式地講應該叫正則表達式)包含了平常的字符與一系列的特殊字符(稱爲元字符)
1.3.1 文件名對模式
在模式匹配中使用的元字符與在文件名擴展的元字符是不同的。當你在命令行發出一個命令的時候,特殊字符在shell中首先被看到,然後纔是程序,所以沒有被引號引起來的元字符被shell中斷修改了擴展部分。例如命令:
$grep [A-Z]* chap[12]
不能被shell轉換爲:
$grep Array.c Bug.c Comp.c chap1 chap2
這樣就開始在文件Bug.c Comp.c,chap1,chap2中查找Array.c字串。爲了通過shell並把特殊字符傳遞給grep,要像以下這樣使用引號:
$grep "[A-Z]*" chap[12]
雙引號在大部分情況下就足夠了,但是單引號是最安全的用法。
注意在模式匹配中,"?"會匹配0個或1個正則表達式的實例;在文件名擴展中,?匹配一個字符。
1.3.2 元字符
同的元字符有不同的意思,這樣根它們在什麼地方用有關係。特別地,正則表達式被用來在文本中進行搜索,同時元字符在處理有不同的集的文本替換上常被使用。這些集之間互相也不相同,這一節就講述了這些元字符在搜索和替換的時候是如何使用的,並說明了不同的變量在不同的應用程序中的具體的描述。
1.3.2.1 搜索模式
在下面的表中的字符只在搜索模式中有特殊的意義:
字符 模式
. 匹配除去新行之外的任意單個字符。在awk中可以匹配空行
* 匹配任何(或沒有)個在它之前的字符。之前的字符可以是一個正則的表達式。比如說,因爲.可以表示任何字符,則.*就表示"匹配任何數量的任意字符"
^ 在一行或一個字符串的開始部分匹配之後的正則表達式
$ 在一行或一個字符串的尾部部分匹配之前的正則表達式
/ 取消下一個字符的特殊意義
[] 匹配任何一個用括號括着的字符。連字符"-"表示了連續的一個字符的範圍。^符號表示了匹配任何一個不在括號內的字符在第一個字符位置爲一個連字符或反括號被認爲是列表中的一個元素。所有的元字符都被認爲是列表中的一個成員
{n,m} 匹配在之前的一個字符的出現範圍。之前的字符也可以是元字符,{n}匹配了正好出現n次;{n,}匹配至少出現n次{n,m}匹配了出現n次到m次。n,m必須是大於0小於255的。
/{n,m} 就像{n,m}一樣的,但是只是在括號之前加了一個反斜扛.
/(/) 把在/(和/)之間包含着的模式存放在一個特殊的存儲空間中.最多9個模式可以被存放在一行中。被子模式匹配的文本可以通過/1到/9進行“回放”
/n 回放由/(和/)括起來的第n個子模式。n是從1到9的數字。以最左位置爲1開始.
/</> 匹配以/<開始的或以/>結束的詞中的字符
+ 匹配一個或多個前述的正則表達式的實例
? 匹配零個或一個前述的正則表達式的實例
| 匹配在之前或之後指定的正則表達式。
() 匹配一個括起來的一組正則表達式
很多unix系統允許在方括號括起來的一組字符裏使用POSIX字符集.就是指用[:和:]括起來的內容。例如[:alnum:]就匹配一個文字數字的字符
字符集類 匹配的字符
alnum 文字數字字符
alpha 字母字符
blank 空格或TAB
cntrl 控制字符
digit 十進制數字
graph 非空格字符
lower 小寫字符
print 可打印的字符
space 空格字符
upper 大寫字符
xdigit 十六進制數字
1.3.2.2 替換模式
下表中的字符只在替換模式中有特殊的含義:
字符 模式
/ 關閉之前字符的特殊含義
/n 存儲用/(和/)保存的n個模式匹配得到的文本。n是從1到9的數字,1是從左端開始的位置
& 重用搜索模式匹配的文本以做爲替換模式
~ 重用之前的替換模式爲當前的替換模式。只能爲在替換模式中的唯一一個字符(ex和vi)
% 重用之前的替換模式爲當前的替換模式。只能爲在替換模式中的唯一一個字符(ed)
/u 把當前替換模式的第一個字符轉爲大寫
/U 把整個替換模式轉爲大寫。
/l 把當前替換模式的第一個字符轉爲小寫
/L 把整個替換模式轉爲小寫
/E 關閉之前的/U或/L
/e 關閉之前的/u或/l
1.3.3 元字符,以unix程序來列舉
一些元字符對於一個程序來說是有效的,但是對於另一個也可能是無效的。在哪個unix程序中有效的我們在下表中將標出.(這個表對於SVR4和Solaris以及大多數unix系統都是正確的,但是對於你的系統來說並不一定總是執行有效的)用"P"標記的項表示是POSIX標準指定的。
符號 ed ex vi sed awk grep egrep 動作
. Y Y Y Y Y Y Y 匹配任意一個字符
* Y Y Y Y Y Y Y 匹配0個或多個之前的字符
^ Y Y Y Y Y Y Y 匹配一行或一個字符串的開始部分
$ 匹配一行或一個字符串的結束部分
/ Y Y Y Y Y Y Y 不匹配之後的字符
[] Y Y Y Y Y Y Y 從一個字符集中匹配一個字符
/( /) Y Y Y Y Y 爲以後的回放來存放模式
/n Y Y Y Y Y 重放之前存儲的某個模式
{ } YP YP 匹配一個範圍的實例
/{ /} Y Y Y 匹配一個範圍的實例
/< /> Y Y Y 在一個詞的詞首或詞尾匹配
+ Y Y 匹配之前的一個或多個字符
? Y Y 匹配之前的零個或一個字符
| Y Y 隔離匹配的選擇
() Y Y 用於匹配的一組表達式
注意在ed,ex,vi,sed中,你可以指定搜索模式(在左)也可以指定替換模式(在右).在表中列出的元字符只在搜索模式中有效.
在ed,ex,vi和sed中,以下的元字符只在替換模式中有效:
符號 ex vi sed ed 動作
/ Y Y Y Y 不匹配後一個字符
/n Y Y Y Y 匹配在/(和/)中存儲的模式
& Y Y Y Y 匹配搜索模式中的文本
~ Y Y 重用之前的替換模式
% Y 重用之前的替換模式
/u/U Y Y 把字符變爲大寫
/l/L Y Y 把字符變成小寫
/E Y Y 關閉/U或/L
/e Y Y 關閉/u或/l
1.3.4 搜索中的實例
當與grep或egrep同時使用的時候,正則表達式應該用引號引起來.(如果模式中包含$,則你必須要使用單引號)當與ed,ex,sed和awk使用正則表達式的時候,它們總要由/包圍起來(awk除外),任何分界符都有效。以下是幾個模式的實例:
模式 匹配的結果
bag bag字符串
^bag 以bag開始的一行
bag$ 以bag結束的一行
^bag$ 只包含bag的一行
[Bb]ag Bag或bag
b[aeiou]g 第二個字符是一個字音字母
b[^aeiou]g 第二個字母是一個輔音字母
b.g 第二個字母是任意字母
^...$ 任何只包含三個字符的一行
^/. 任何以一個"."開始的一行
^/.[a-z][a-z] 同前一個模式,之後的兩個字符爲小寫
./[a-z]/{2/} 與之前的模式相同,僅在ed,grep和sed中使用
^[^.] 任何一個不以"."開始的一行.
bugs* bug,bugs,bugss等等
"word" 用引號引起來的詞
"*word" 一個詞,有或沒有引號引着
[A-Z][A-Z]* 一個或多個大寫字母
[A-Z]+ 同上,只有在egrep和awk使用
[[:upper:]]+ 同上,POSIX下的egrep或awk使用
[A-Z].* 一個大寫的字母,後接以0個或多個字符
[A-Z]* 0個或多個大寫字符
[a-zA-Z] 任意一個字母,不管是大寫還是小寫
[^0-9A-Za-z] 任何的一個符號或空格(不是字母或數字)
[^[:alnum:]] 同上,用POSIX的字符集
egrep或awk模式 匹配的結果
[567] 5,6,7中的一個數字
five|six|seven 一個爲five或six或seven的詞
80[2-4]?86 8086,80286,80386或80486
80[2-4]?86|Pentium 8086,80286,80386或80486或Pentium
compan(y|ies) company或companies
ex或vi的模式 匹配的結果
/<the 像theater,there或the這樣的詞
the/> 像breathe,seathe或the這樣的詞
/<the/> the
ed, sed或grep模式 匹配的結果
0/{5,/} 在一行中有五個以上的0
[0-9]/{3/}-[0-9]/{2/}-[0-9]/{4/}nnn-nn-nnnn格式的數字
/(why/).*/1 出現兩次why的一行
/([[:alpha:]_][[:alnum:]_.]*/) = /1; C++賦值語句
1.3.4.1 搜索並替換的例子
以下的例子說明了sed或ex中的元字符。注意ex命令以冒號開始。
標的時候空格記爲S,TAB記爲T
命令 結果
s/.*/( & )/ 重做整行,但是加入圓括號
s/.*/mv & &.old/ 變換mv命令一個詞列表(每行一詞)
/^$/d 刪除空行
:g/^$/d 在ex中的上面命令
/^[ST]*$/d 刪除空行,和僅包含空格和[]的行
:g/^[ST]*$/d 同上,在ex中使用
s/SS*/S/g 把一個或多個空格變爲一個
:%s/SS*/S/g 同上,在ex中使用
:s/[0-9]/Item &:/ 把一個數字變成一個當前行的項標
:s 在第一次出現的時候重複替換
:& 同上
:sg 同上,但是是對於任意一次出現的時候
:&g 同上
:%&g 在所有的行上重複替換
:.,$s/Fortran//U&/g 從當前行到最後一行,把詞換爲大寫
:%s/.*//L&/ 整個文件變爲小寫
:s//<.//u&/g 對於當前行的所有的詞的首字符轉爲大寫
:%s/yes/No/g 在全文中把詞替換爲No
:%s/Yes/~/g 在全文把一個不同的詞替換爲No
最後,這裏有一些sed的替換詞的例子.一個簡單的替換兩個字的例子如下:
s/die或do/do或die/
真正的技巧是對替換的變量模式使用緩衝。例如,用緩衝進行替換:
s//([Dd]ie/) or /([Dd]o/)//2 or /1/