前言 :
Perl 有需多異於其他語言的特色. 在這些特色中最重要的一項就是對正則表示式的強力支援. 這些支援提供了快速, 彈性與可靠的字串處理能力.
何謂正則表示式 :
正則表示式 (regular expression) 在 Perl 裡通常稱為樣式 (Pattern), 是一個 "符合" 或 "不符合" 特定字串的範本. 也就是說, 有無限可能的文字字串, 而任何一個樣式都可以將這個無限集合分成兩個群組 : 符合此樣式與不符合的. (Wiki : 正則表示式)
樣式的簡易用法 :
要以某個樣式 (正則表示式) 來比對 $_ 的內容, 請將它放在兩個斜線 (/) 之間, 如下所示 :
/abba/ 運算式會在 $_ 中尋找由 "abba" 這四個字符所組成的字串 ; 如果找到了, 它就會傳回真. 上面範例它不止找到一個字串, 但是這並不會影響結果. 只要找到了就算是比對成功 ; 如果沒有就算是比對失敗. 所有能在雙引號內字串使用的 "倒斜線規避序列", 也都可以在樣式裡使用.
- 關於中介字符
當然如果樣式只能比對簡單的文字字串, 那還不算是特別有用. 所以還有許多稱為中介字符 (metacharacter) 的特殊符號, 它們在正則表示式中具有特別的意義.
舉例來說 , 點號 (.) 是個萬用字符或稱通配符. 它會符合換列字符 (\n) 以外的所有單一字符. 因此 betty 將會符合 /bet.y/ 這個樣式. 注意的是點號只用來比對一個字符. 所以如果你想要比對字串中的句號 (period) , 雖然也可以用點號, 但這樣也會符合其他不相干的字符. 要是希望點號只能符合句號本身, 在前面加上倒斜線就行了. 此規則亦適用於任何其他 Perl 正則表示式裡所用到的中介字符 ; 在中介字符前面加上倒斜線, 就會使它失去中介字符的特殊作用.
因此倒斜線也是其中一個中介字符. 如果要得到真正的倒斜線, 請用兩個倒斜線表示.
- 簡單的量詞
在一個樣式中重復某些字眼, 是很常見的情況. 星號 (*) 會比對它前一個字符/項目零次或更多次. 因此 /fred\t*barney/ 這個樣式將會符合任何在 fred 與 barney 之間含有任意數目的跳格字符. 因為星號表示 "零或更多", 所以兩個字符之間可以有數百或完全沒有跳格字符. 但是除跳格字符就不會出現其它字符了.
如果除了跳格字符外, 還想比對其它字符該怎麼辦? 點號會比對任何字符. 因此 ".*" 會比對任何字符無限次. 也就是不管 fred 與 barney 之間夾著 "隨便甚麼東西" 都會符合樣式 /fred.*barney/. 因此我們稱 ".*" 為 "隨便什麼東西" 樣式.
星號的正式名稱是量詞 (quantifier), 意思是說它只訂了前一個項目的數量. 但是它不是唯一的量詞 ; 加號 (+) 是另外一個. 加號會比對前一個項目一次以上, 例如 /fred +barney/ 會符合在 fred 與 barney 之間用空格隔開, 而且只用空格隔開的字串. (空格不是中介字符) 它不會符合 fredbarney, 因為加號表示成在兩個名稱間必須要有一個以上的空格.
第三個量詞和星號與加號類似, 但是它的限制更為嚴格. 這個量詞是問號 (?), 表示前一個項目是可有可無. 也就是說前一個項目可以出現一次或是不出現. 因為這三個量詞指定了前一個項目重複的次數, 所以他們都必須接在某個東西之後.
- 樣式分組
在數學中, 圓括號 (()) 具有分組的作用. 在樣式比對中, 它也是中介字符. 舉例來說 樣式 /fred+/ 會符合像 fredddddd 這樣的字符, 可是這種字串實際上不常出現. 不過樣式 /(fred)*/ 會符合像 fredfredfred 這樣的字串, 這樣比較可能是你想要的.
圓括號讓我們得以直接在樣式比對中重複使用部分的字串. 透過回溯參照 (back reference) 我們可以引用圓括號中所找到的內容. 回溯參照會被表示成一個倒斜線後面跟著一個數字, 例如 \1, \2 等等. 數字用於表示特定的圓括號分組. 以圓括號括住點號, 可用於比對任何非換列字符. 回溯參照 \1 可用於將圓括號中所找到的內容再拿來處理 :
樣式 (.)\1 讓我們找到兩個相同且緊接在一起的字符. 這裡會找到 bb.
回溯參照不必緊接在圓括號分組之後. 下面樣式比對用於比對 "y 之後跟著四個非換列字符", 並且以回溯參照 \1 指出還要比對 "d 之後跟著相應圓括號分組所找到的內容" :
我們可以同時使用多個圓括號分組, 每個分組有自己的回溯參照. 參考範例如下 :
$_ = "yabba dabba doo";
但問題來了, 我們怎麼知道哪個數字對應到哪個分組? 還好 Larry 做法十分簡單 : 計算左圓括號的個數並忽略套疊的情況 :
$_ = "yabba dabba doo";
也許將正規表示式寫成下面形式會比較容易計算 :
Perl 5.10 為回溯參照提供一個新的表示法. 此表示法使用的不是倒斜線與一個數字, 而是使用 \g{N}, 其中 N 是你想要使用之回溯參照的編號. 在樣式中使用此表示法將可以避免一些誤判的情形. 所以我們可以將回溯參照與樣式的字面部分區開來 :
使用 \g{N} 表示法時, 我們還可以使用負數. 除了以絕對數字編號來指定圓括號分組 (一般回溯參照), 我們還可以使用相對數字編號來指定圓括號分組 (相對回溯參照). 例如我們可以使用 -1 將前面的例子改寫成 :
- 擇一比對
豎線 (|) 在這裡, 使用上通常念為 "或" (or), 表示左邊或右邊符合. 也就是說如果豎線左半邊的樣式比對失敗, 豎線右邊有可能會比對成功. 因此 /fred|barney|betty/ 對任何提到 fred 或 barney 與 betty 的字串都進行比對. 現在我們可以使用 /fred( |\t)+barney/ 這般樣式, 來比對 fred 和 barney 之間是否存在空格, 跳格或兩者的組合. 加號表示重複一次或更多次 ; 每次只要有重複, ( |\t) 都會對空格與跳格進行比對. 若你希望 fred 與 barney 之間的字符全都一樣, 你可以將上述樣式改成這樣 : /fred( +|\t+)barney/ .如此一來中間的分隔符一定全是空格或全是跳格.
字符集 :
字符集 (character class) 就是方括號 ([]) 一連串可能的字符. 它只會符合單一字符, 但該字符可以是字符集裡的任一個. 舉例來說字符集 [abcwxyz] 會符合這七個字符中的任何一個. 為了方便你可以使用連字符 (-) 來指定某個範圍的字符 ; 因此上述字符集也可以寫成 [a-cw-z], 然而這麼做並不會省掉多少打字的功夫. 比較常見用法就是建立一個像 [a-zA-Z] 這樣的字符集, 來比對 52 個字母中的一個.
定義字符集時, 你可以使用與 "雙引號內字串" 相同的字符簡寫, 因此字符集 [\000-\177] 將會符合任何 7 位元的 ASCII 字符. 簡單範例如下 :
有時候指定字符集以外的字符會比定字符集來的容易. 在字符集開頭加上脫字符號 (^) 可用來排除字符集. 也就是說 [^def] 會符合這三個字符以外的任何字符, 而 [^n\-z] 則會符合 "n", 連字符與 "Z" 以外的任何字符.
- 字符集簡寫
某些字符集十分常用, 因此具有自己的簡寫. 比方說代表任意數字的字符集 [0-9] 可以簡寫成 \d. 因此上面提到之 HAL 範例的樣式, 可以改寫成 /HAL-\d+/.
簡寫 \w 就是所謂的 "單字" (word) 字符 : [A-Za-z0-9_]. 如果你用的單字是由普通的字母, 數字與底線符號組成, 將可以使用 \w 來取代. 當然 \w 並不會符合一個單字 ; 它只會符合 "單字" 裡的一個字符. 雖然如此, 要比對完整的單字時, 只要使用加號修飾符就行了. 例如樣式 /fred \w+ barney/ 可用於比對 "fred, 一個空格,一個單字,一個空格,barney".
\s 簡寫擅長處理空白 ; 它相當於[\f\t\n\r ] . 也就是說, 它等於是個字符集, 裡面包含五種空白字符 : 跳頁 (\f), 跳格(\t), 換列(\n), 回行首(\r) 與空格.
- 簡寫的排除
有時候你也許想使用以上三種簡寫的反義. 這時你只需要將之轉成對應的大寫如 \D, \W 與 \S 就行了. 它們所符合的字符就是相應小寫形式所不符合的字符. 這些簡寫既可以做為樣式的獨立字符集, 也可以用為方括號字符集的一部份. 也就是說 /[\dA-Fa-f]+/ 可以用來比對十六進制數值. 另一個複合字符集是 [\d\D], 用來表示任何數字或非數字. 也就是說它會符合任何字符! 這是比對任意字符(包括換列字符)的常見做法.
* [工具收集] Architects Regression Tester
* regexlib.com :
Perl 有需多異於其他語言的特色. 在這些特色中最重要的一項就是對正則表示式的強力支援. 這些支援提供了快速, 彈性與可靠的字串處理能力.
何謂正則表示式 :
正則表示式 (regular expression) 在 Perl 裡通常稱為樣式 (Pattern), 是一個 "符合" 或 "不符合" 特定字串的範本. 也就是說, 有無限可能的文字字串, 而任何一個樣式都可以將這個無限集合分成兩個群組 : 符合此樣式與不符合的. (Wiki : 正則表示式)
樣式的簡易用法 :
要以某個樣式 (正則表示式) 來比對 $_ 的內容, 請將它放在兩個斜線 (/) 之間, 如下所示 :
- $_ = "yabba dabba doo";
- if(/abba/) {
- print "Match!!\n";
- }
/abba/ 運算式會在 $_ 中尋找由 "abba" 這四個字符所組成的字串 ; 如果找到了, 它就會傳回真. 上面範例它不止找到一個字串, 但是這並不會影響結果. 只要找到了就算是比對成功 ; 如果沒有就算是比對失敗. 所有能在雙引號內字串使用的 "倒斜線規避序列", 也都可以在樣式裡使用.
- 關於中介字符
當然如果樣式只能比對簡單的文字字串, 那還不算是特別有用. 所以還有許多稱為中介字符 (metacharacter) 的特殊符號, 它們在正則表示式中具有特別的意義.
舉例來說 , 點號 (.) 是個萬用字符或稱通配符. 它會符合換列字符 (\n) 以外的所有單一字符. 因此 betty 將會符合 /bet.y/ 這個樣式. 注意的是點號只用來比對一個字符. 所以如果你想要比對字串中的句號 (period) , 雖然也可以用點號, 但這樣也會符合其他不相干的字符. 要是希望點號只能符合句號本身, 在前面加上倒斜線就行了. 此規則亦適用於任何其他 Perl 正則表示式裡所用到的中介字符 ; 在中介字符前面加上倒斜線, 就會使它失去中介字符的特殊作用.
因此倒斜線也是其中一個中介字符. 如果要得到真正的倒斜線, 請用兩個倒斜線表示.
- 簡單的量詞
在一個樣式中重復某些字眼, 是很常見的情況. 星號 (*) 會比對它前一個字符/項目零次或更多次. 因此 /fred\t*barney/ 這個樣式將會符合任何在 fred 與 barney 之間含有任意數目的跳格字符. 因為星號表示 "零或更多", 所以兩個字符之間可以有數百或完全沒有跳格字符. 但是除跳格字符就不會出現其它字符了.
如果除了跳格字符外, 還想比對其它字符該怎麼辦? 點號會比對任何字符. 因此 ".*" 會比對任何字符無限次. 也就是不管 fred 與 barney 之間夾著 "隨便甚麼東西" 都會符合樣式 /fred.*barney/. 因此我們稱 ".*" 為 "隨便什麼東西" 樣式.
星號的正式名稱是量詞 (quantifier), 意思是說它只訂了前一個項目的數量. 但是它不是唯一的量詞 ; 加號 (+) 是另外一個. 加號會比對前一個項目一次以上, 例如 /fred +barney/ 會符合在 fred 與 barney 之間用空格隔開, 而且只用空格隔開的字串. (空格不是中介字符) 它不會符合 fredbarney, 因為加號表示成在兩個名稱間必須要有一個以上的空格.
第三個量詞和星號與加號類似, 但是它的限制更為嚴格. 這個量詞是問號 (?), 表示前一個項目是可有可無. 也就是說前一個項目可以出現一次或是不出現. 因為這三個量詞指定了前一個項目重複的次數, 所以他們都必須接在某個東西之後.
- 樣式分組
在數學中, 圓括號 (()) 具有分組的作用. 在樣式比對中, 它也是中介字符. 舉例來說 樣式 /fred+/ 會符合像 fredddddd 這樣的字符, 可是這種字串實際上不常出現. 不過樣式 /(fred)*/ 會符合像 fredfredfred 這樣的字串, 這樣比較可能是你想要的.
圓括號讓我們得以直接在樣式比對中重複使用部分的字串. 透過回溯參照 (back reference) 我們可以引用圓括號中所找到的內容. 回溯參照會被表示成一個倒斜線後面跟著一個數字, 例如 \1, \2 等等. 數字用於表示特定的圓括號分組. 以圓括號括住點號, 可用於比對任何非換列字符. 回溯參照 \1 可用於將圓括號中所找到的內容再拿來處理 :
- $_ = "yabba dabba doo";
- if(/(.)\1/) { #Find bb
- print "Get two same chars stick to each other!!!\n"
- }
回溯參照不必緊接在圓括號分組之後. 下面樣式比對用於比對 "y 之後跟著四個非換列字符", 並且以回溯參照 \1 指出還要比對 "d 之後跟著相應圓括號分組所找到的內容" :
- $_ = "yabba dabba doo";
- if(/y(....) d\1/) { # match yabba dabba
- print "Get it!!\n"
- }
$_ = "yabba dabba doo";
- if(/y(.)(.)\2\1/) { # match 'abba'
- print "Get it!!\n"
- }
$_ = "yabba dabba doo";
- if(/y((.)(.)\3\2) d\1/) { # match 'abba'
- print "Get it!!\n"
- }
- ( # 第一個左圓括號
- (.) # 第二個左圓括號
- (.) # 第三個左圓括號
- \3
- \2
- )
- $_ = "aa11bb";
- if(/(.)\g{1}11/) { # match 'aa'
- print "Get it!!\n"
- }
- $_ = "aa11bb";
- if(/(.)\g{-1}11/) { # match 'aa'
- print "Get it!!\n"
- }
豎線 (|) 在這裡, 使用上通常念為 "或" (or), 表示左邊或右邊符合. 也就是說如果豎線左半邊的樣式比對失敗, 豎線右邊有可能會比對成功. 因此 /fred|barney|betty/ 對任何提到 fred 或 barney 與 betty 的字串都進行比對. 現在我們可以使用 /fred( |\t)+barney/ 這般樣式, 來比對 fred 和 barney 之間是否存在空格, 跳格或兩者的組合. 加號表示重複一次或更多次 ; 每次只要有重複, ( |\t) 都會對空格與跳格進行比對. 若你希望 fred 與 barney 之間的字符全都一樣, 你可以將上述樣式改成這樣 : /fred( +|\t+)barney/ .如此一來中間的分隔符一定全是空格或全是跳格.
字符集 :
字符集 (character class) 就是方括號 ([]) 一連串可能的字符. 它只會符合單一字符, 但該字符可以是字符集裡的任一個. 舉例來說字符集 [abcwxyz] 會符合這七個字符中的任何一個. 為了方便你可以使用連字符 (-) 來指定某個範圍的字符 ; 因此上述字符集也可以寫成 [a-cw-z], 然而這麼做並不會省掉多少打字的功夫. 比較常見用法就是建立一個像 [a-zA-Z] 這樣的字符集, 來比對 52 個字母中的一個.
定義字符集時, 你可以使用與 "雙引號內字串" 相同的字符簡寫, 因此字符集 [\000-\177] 將會符合任何 7 位元的 ASCII 字符. 簡單範例如下 :
- $_ = "The HAL-900 requires authorization to continue.";
- if(/HAL-[0-9]+/) {
- print "Match HAL Type!\n";
- }
- 字符集簡寫
某些字符集十分常用, 因此具有自己的簡寫. 比方說代表任意數字的字符集 [0-9] 可以簡寫成 \d. 因此上面提到之 HAL 範例的樣式, 可以改寫成 /HAL-\d+/.
簡寫 \w 就是所謂的 "單字" (word) 字符 : [A-Za-z0-9_]. 如果你用的單字是由普通的字母, 數字與底線符號組成, 將可以使用 \w 來取代. 當然 \w 並不會符合一個單字 ; 它只會符合 "單字" 裡的一個字符. 雖然如此, 要比對完整的單字時, 只要使用加號修飾符就行了. 例如樣式 /fred \w+ barney/ 可用於比對 "fred, 一個空格,一個單字,一個空格,barney".
\s 簡寫擅長處理空白 ; 它相當於[\f\t\n\r ] . 也就是說, 它等於是個字符集, 裡面包含五種空白字符 : 跳頁 (\f), 跳格(\t), 換列(\n), 回行首(\r) 與空格.
- 簡寫的排除
有時候你也許想使用以上三種簡寫的反義. 這時你只需要將之轉成對應的大寫如 \D, \W 與 \S 就行了. 它們所符合的字符就是相應小寫形式所不符合的字符. 這些簡寫既可以做為樣式的獨立字符集, 也可以用為方括號字符集的一部份. 也就是說 /[\dA-Fa-f]+/ 可以用來比對十六進制數值. 另一個複合字符集是 [\d\D], 用來表示任何數字或非數字. 也就是說它會符合任何字符! 這是比對任意字符(包括換列字符)的常見做法.
* [工具收集] Architects Regression Tester
* regexlib.com :
This message was edited 4 times. Last update was at 25/08/2010 22:29:14
沒有留言:
張貼留言