Perl 有很多其它語言所沒有的特性,這其中對正則表達式(regular expression)的強大支持是它最為突出的一個亮點。正則表達式使得 perl 在處理文本時具有非常強大的優勢:快速,靈活而且很可靠,甚至可以說,強大文本處理能力,是 perl 在眾多語言中最為閃耀的一個特點。 因此學習 perl 的過程,必然也是學習正則表達式的過程,這或許多少給 perl 的學習增加了些少的負擔,但好在正則表達式並不是 perl 所獨有的, 它是一門使用非常廣泛的語言,在很多工具及其它編程語言中都有廣泛的支持,比如:grep,awk,sed,vi 等。 它是如此的常見,以致於編程人員在很多場合都無可避免的要與之打交道,因此掌握好正則表達的好處是非常明顯的,好在它的語法也很簡單,學習起來也不算太難。
在 Perl 或其它一些語言及工具中,正則表達式通常也會叫為“模式"(pattern),正則表達式本質上來說是一個字符串模板,用來確認某個字符串是否符合這個模板的格式,任何一個字符串,要么符合這個模板,要么不符合這個模板。具體到在Perl中,正則表達式是用"/"圍起來的,比如:($string =~ /pattern/)。在這里我們暫且稱 string 為匹配串,只有當 string 匹配了 ”pattern" 這個串時,這個表達式才是true,反之為false。如: "abc ef ffff" =~ /ef/ 為 true,"abc" =~ /ee/ 為 false。
當然上面的例子只是最簡單的情形,如果正則表達式只能做這樣單純的純字符匹配,那它就不可能這么強大。正則表達式通過一類特殊的字符,我們稱為元字符或通配符(meta character)來進行字符的模糊表示,它們在匹配的過程中代表特殊的含義。下面我們就進行簡單的介紹。
(1) 點號(.),它用來匹配任意一個單字符(\n 排除在外,后面我默認不再提這個例外)。
所以: "twoon" =~ /tw.on/ 為 true
“twvon" =~ /tw.on/ 也為 true.
點號在正則表達式中是有特殊含義的,有時我們可能也要匹配點號,這時就需要轉義一下。
"twoo.n" =~ /twoo\.n/ 為true.
正則表達中,所有其它的通配符也都可以用同樣的方式進行轉義,表示直接匹配通配符,去除它的特殊含義。
你可以看到\也是一個通配符,如果要匹配它也是同樣的道理。
"two\\on" =~ /two\\on/ 為true.
(2) 星號(*) : 星號代表匹配它前面一個字符任意遍(0或任意次),它是一數量詞(quantifier),必須跟在其它字符的后面,否則這個表達式不正確。
如: ”twoon" =~ /two*n/ 為true
“twn" =~ /two*n/ 也為true.
"twoon" =~ /*twoon/ 表達式不正確,*必須跟在其它符號后面.
同時星號也可以匹配點號(.),點號代表任意非回車字符,因此, (.*)就代表任意字符任意次。這是一個慣常的用法,如: /twoon.*walks/ 能匹配任意包含"twoon"在前,"walks“在后的字符串。所以(.*)也被稱為:any old junk. 匹配任何東西。
(3) 加號(+): 加號是一個與星號(*)類似的通配符,它也是數量詞,表示匹配前面的字符一次或多次(至少一次).
它與星號的差別就在這里,星號可以匹配0次,加號則必須一次以上。
如:"twoon" =~ /two+n/ 為true.
"twn" =~ /two+n/ 為false.
(4) 問號(?): 問號也是一個數量詞,它代表匹配前一個字符0或1次。
如: "twoon" =~ /twoo?n/ 為true
"twoon” =~ /two?n/ 為false.
"twn" =~ /two?n/ 為true.
(5) 括號(()): 括號用來表示一個組合,前面我說數量詞作用在前一個字符上,這個說法事實上不准確,應該說是作用在一個組合上,一個字符是一個組合,但多個字符也可以成為組合。括號就是用來表示一個組合,被括號括起來的就是一個組合。
如: "twoon" =~ /tw(o)*n/ 為true.
"twoon" =~ /tw(oo)*n/ 為true
"twowon" =~ /t(wo)*n/ 為true.
"twoon" =~ /t(wv)*oon/ 為false.
“twoon" =~ /t(wo)+on/為true.
"twon" =~ /t(wo)+on/為false.
括號里可以放置任何字符,也可以放置其它通配符,如 "aaabcc" =~ /(aa+b)?cc/
(6) 引用通配符:反斜杠加上數字是所謂引用通配符(back reference): \1 \2 \3 等,它的作用是引用前面的某個括號元組,如:
"twoonwo" =~ /t(wo)on\1/ 為true
乍看起來,似乎作用不明顯,如上例,我們完全可以不用\1,而寫成這樣: /t(wo)on(wo)/
在上面的例子里,這個質疑是可以理解的。但有時,我們的括號元組可能這樣寫的: (we...) 因為點號代表任意字符,如果我們后面要作用這個元組,不用引用通配符, 我們根本無法引用,具體看例子:
”weabceeweabc" =~ /(we...)ee\1/ 為 true。
“weabceeweabc" =~ /(we...)ee(we...)/ 為 true
”weabceewecdf" =~ /(we...)ee(we...)/ 也為 true.
從第2,3個例子,我們可以看區別。\1 表示的是與前一個元組完全一樣的匹配。而 \1,\2,\3等,則分別表示,從左往右數第幾個元組。
“abcdef def abc" =~ /(...)(...) \2\1/ 為 true.
在 perl 中,引用通配符中支持從1~9,寫法上很活,你既可直接\1 \2 ...\9這樣來寫,也可以寫成 \g{1] ,\g{2},.....\g{9}。后面一種寫法相對復雜些,但有助於perl來理解你想表達的含義。因為反斜杠在程序語言中有特殊的信念,通常表達轉義,perl 在遇到反斜杠時,它會去猜你想表達的什么。所以如果你寫一個類似: \123這樣的東西,它就不知怎么去解析,你是想表達 \1+23,引用后面跟着數字,還是,\12+3,或 \123,轉義符后面跟數字是可以表示轉義一個8進制數字的。因此這里產生了歧義。perl 5.10 於是引入了 \g{N}這種表述方式來表示引用通配符。N 甚至可以是負數,當是用負數是,它表示一個相對位置。表示從當前位置開始往左數,第N個元組,如:
"twooavvboonn" =~ /tw(oo)a(vv)b\{-2}(nn)/ 為true.
(7) 中括號[]: 中括號用來表示一個字符集合(character set)
字符集合,顧名思義,就是字符的集合,集合的元素放在中括號里,表示每次匹配中其中的一個,如: "twoon” =~ /[tw]woo/ 為 true
有時如果這個集合有很多元素,如26個字母,數字等,一個個地寫在中括號里,未免太麻煩太蠢笨,這時可以用連字符(hyphen)來表示一個范圍,如:[a-z]表示小寫字母的集合,[a-zA-Z]表示大小寫字母的集合。
上面的用法用於提供范圍來選擇,但有時不匹配某個范圍也是很常見的匹配需求,這時我們可以在集合的開頭放一個脫字符 ^ (caret). 這種寫法表示,匹配任何不在該集合中的字符,與上面的用法剛好相反。如:"twoon" =~ /[^two]woon/ 為false
“ewoon" =~ /[^two]woon/ 為true
由上面的用法,可知 ^,- 這兩種符號在集合中有特殊含義,如果我們們想在集合中表示這兩個字符,就也要轉義一下。如:[\^ab\-]
有些字符集合是很常用的,如字母,數字等,perl提供了一些縮寫來表示這些常用的集合,如:\d表示一個數字,等價於[0-9],這些特殊字符包括如下 :
\w -- (小寫w) 表示字母或數字,等價於 [a-zA-Z0-9]
\W -- (大寫W)非字母且非數字,與\w相反
\s -- (小寫s)匹配一個空格字符,包括:空格,換行,回車,tab,等價於[ \n\r\t\f]
\S -- (大寫S)匹配非空格字符,\s的相反
\d -- 表示10進制數字,等價於 [0-9]
(8) 大括號:{}
大括號的作用是指定重復前面一個字符多少遍:
{N} 重復N遍
{n,m} 重復 n~m 遍
{n,} 至少重復n遍
{,m} 至多重復m遍
示例:"twoon" =~ /two{2}n/ 為true.
(9) ^,& 這兩個通配符用來表示在匹配串的頭部或尾部匹配。
一般我們寫這種: "twoon" =~ /oo/ 正則表達式的時候,匹配是從"twoon"的開始一路匹配下去,如tw != oo,就繼續往下匹配,但有時候我們可能只想匹配一下開頭或結尾,這時^,&就派上用場了。^用於匹配字符串的開關,&用於匹配字符串的結尾。如: "twoon" =~ "^tw" 為true.
“twoon” =~ “oo" 為true
"twoon" =~ "^oo" 就為false.
”twoon" = "on&" 為true.
"twoon“ = ”oo&" 為false
(10) “或" 通配符: 正則表達式用豎線 | 表示或, (ab | cd) 表示匹配豎線左右的字符組之一,如果左右的字符數超過一個,它必須和括號一起使用。
如: "twoon” =~ /t|ewoon/ 結果為true
"twoon" =~ /(tw|ee)oon/ 結果為true
"twoon" =~ /(ee|gs)oon/ 結果為false
上面簡單地介紹了正則表達式中各種通配符的含義及用法,可以看出,正則表達式在語法上還算是簡單的,但這並不代表它也只會做簡單的事情,事實上,正則表達式也可以寫得很復雜,語法的簡單或復雜與該語言功能強大與否並沒有太多直接的聯系。學習正則表達式可以讓我們在很多場合下受益,特別是在使用unix類系統下的各種工具時,只是這種語言也和很多其它很多語言一樣,學而不用就很容易忘。本文只是簡單的介紹了一下它的基本語法,基本寫法,要想做到熟能生巧,就需要在日常工作中,多練習,多操作,多留心了。