2009年5月27日 星期三

Perl 的正規表示式

在 Perl 程式中我們常會需要比較某個字串是否合於某個樣式, 以便決定是否對這個字串資料作進一步的處理, 這裡的樣式就是所謂的正規表示式

一個簡單的例子

if ( $str =~ /abc/ ) {
print $str;
}

上面這個例子是說如果 $str 比對符合有 abc 這個字串, 就將 $str 印出來

1. =~ 代表的是比對符合
2. !~ 可以用來表示比對不符合的情形
3. 如果要 case insensitive 比對, 用 /abc/i 代替 /abc/ 即可
4. / 代表比對邊界的開始與結束
5. 如果要比對的字串中含有 / 字元, 以 $str 是否比對符合有 "/home" 字串為例, 比對敘述可以有下面兩種處理方式
a. $str =~ /\/home/
將 / 字元前面加一反斜線 \, 讓字串中的 / 字元不具有比對邊界字元的意思
b. $str =~ m!/home!
透過 m 命令將邊界字元換成其它字元, 在這裡我們將邊界字元換成 !

更精簡的例子 ( 利用 $_)

if ( /abc/ ) {
print;
}

這個更短的例子看起來有點怪, 其實是因為它隱藏了 $_ 這個內定運算元, 當 Perl 中你看不到運算元時, 表示此時運算元是內定運算元 $_, 上面這個例子其實就是

if ( $_=~/abc/ ) {
print $_;
}

Character Pattern

表示法 意義
任意字母 代表此字母本身
. 代表除換行字元外的任意一個字元
[任意個任意字元] 代表一個在 [] 中出現的字元
[^任意個任意字元] 代表一個不在 [] 中出現的字元

範例
/abcd/
任意含 abcd 的字串
/a.b/
a 帶一個任意字元, 後面接著一個 b
/[abc]xy/
a 或 b 或 c 其後帶著 xy
/[^abc]xy/
abc 以外任一字元帶著 xy

Buildin Character Class

表示法 意義
\d [0-9]
\D [^0-9]
\w [A-Za-z]
\W [^A-Za-z]
\s [ \r\t\n\f]
\S [^ \r\t\n\f]

範例
/[\dA-Fa-f]/
16 進位數字 0..9a..f

Multipler

表示法 意義
* 代表 * 前一個字元出現 0 到任意多次
+ 代表 + 前一個字元出現 1 到任意多次
? 代表 ? 前一個字元出現 0 或 1 次
{repeat} 代表 { } 之前的字元出現 repeat 次

範例
/ab+c/
a 跟著一個以上的b, 再跟著 c, 比如 abc, abbc, abbbc, abbbbc, abbbbbc, abbbbbc.....
/ab{5}c/
a 跟著 5 個 b, 再跟著 c,

Anchor Pattern (定位樣式)

表示法 意義
^ 字首
$ 字尾
\b word boundary
\B not word boundary

範例
/^a.*c$/
a 開頭 c 結尾的任意字串
/\bFred\B/
與 Frederich 符合, 但與 Fred liu 不符合

利用 ( ) 記憶比對結果

當 pattern 中有 ( ) 時, ( ) 中的部份在比對成功時會依序被記錄到 $1, $2, $3.... 這些個變數中,
在 pattern 的其它部份可以分別用 \1, \2, \3... 來引用 $1, $2, $3 的內容

範例
/(b*)a\1/
代表 a, bab, bbabb, bbbabbb, bbbbabbbb .....

當 pattern 中有 ( ) 時, 比對成功後, 記錄在 $1, $2, $3... 的內容可以被程式的其它部份使用

範例
if ( m!\s(\w+)://([\w\d#~%&+:\-\.])/?(.*)\s! ) {
$protocol=$1;
$host=$2;
$path=$3;
}

代換運算

正規表示式除了用來作比對外, 也可以用來做字串代換

表示法 意義
s/原字串 pattern/新字串/ 字串代換(至多一次)
s/原字串 pattern/新字串/g 字串代換(全部代換)
s!原字串 pattern!新字串! 字串代換, 改以 ! 為分隔字元

範例
s/alpha/beta/
將 alpha 換成 beta
s/alpha/beta/g
將所有的 alpha 換成 beta

. 代表任意字元,但不包括換行字元 \n

* 代表比對成功的次數是 0 或 0 次以上

+ 代表比對成功的次數是 1 或 1 次以上

? 代表比對成功的次數是 0 或 1 次 (若用在其它數量修飾子之後,則表示 "比對採不貪心的模式")

^ 代表字串開頭

$ 代表字串結尾

\ 將其後的字元跳脫,使其回歸原字元的涵義,如:\\ , \. , \@ , \? , \*

| 樣式中的 或

( ) 群集

[0-9] 一個數字字元
[^0-9] 非數字
[a-z] 一個英文小寫字母
[^a-z] 非小寫
[A-Z] 一個英文大寫字母
[^A-Z] 非大寫
[a-zA-Z] 英文字母
[^a-zA-Z] 非英文字母

\d 同 [0-9] 數字
\D 同 [^0-9] 非數字
\w 文字, 同 [a-zA-Z0-9_]
\W 非文字,同 [^a-zA-Z0-9_]

\s 空白字元,同 [ \t\n\r\f]
\S 非空白字元,同 [^ \t\n\r\f]

\b 單字的邊界
\B 非單字的邊界

\xnn 16 進位數 nn
\nnn 8 進位數 nnn

{n} 剛好 n 次
{n, } n 次以上
{n, m} 至少 n 次,但不能超過 m 次


更多關於 Regular Expression 的說明請看這裡


以下是相對的一些例子。記住它們皆須被置於 /.../中來使用。

t.e # t 後面跟隨著的任何字元其後跟隨的是 e
# This will match the
# tre
# tle
# but not te
# tale
^f # f 在一行的起始
^ftp # ftp 在一行的起始
e$ # e 在一行的尾端
tle$ # tle 在一行的尾端
und* # un 之後跟髓著零或多個 d 字元
# This will match un
# und
# undd
# unddd (etc)
.* # 任何一個沒有 newline 的字串。這是因為 . 吻合任何字串除了 newline 並且 * 代表零或多個這種情況
^$ # 空無一物的一行

以下是更多其它的選擇。中括弧被用來比對括弧中的任何一個字元,而括弧中的 - 代表 "介於",並且開始的 ^ 代表 "無":

[qjk]  # q 或 j 或 k 任何一者
[^qjk] # 非 q 或 j 或 k 任何一者
[a-z] # 任何介於 a 到 z 者
[^a-z] # 無小寫字母
[a-zA-Z] # 任何英文字母
[a-z]+ # 任何非零的小寫字元
到此你(妳)或許可以跳到最後的練習部分,剩下的部分僅供參考。

一個垂值的 | 表示 "or" ,並且 (...) 能用來做聚合的作用:

jelly|cream # jelly 或 cream 兩者之一
(eg|le)gs # eggs 或 legs 兩者之一
(da)+ # da 或 dada 或 dadada 或...

Here are some more special characters:

\n  # A newline
\t # A tab
\w # Any alphanumeric (word) character.
# The same as [a-zA-Z0-9_]
\W # Any non-word character.
# The same as [^a-zA-Z0-9_]
\d # Any digit. The same as [0-9]
\D # Any non-digit. The same as [^0-9]
\s # Any whitespace character: space,
# tab, newline, etc
\S # Any non-whitespace character
\b # A word boundary, outside [] only
\B # No word boundary

Clearly characters like $, |, [, ), \, / and so on are peculiar cases in regular expressions. If you want to match for one of those then you have to preceed it by a backslash. So:

\|  # Vertical bar
\[ # An open square bracket
\) # A closing parenthesis
\* # An asterisk
\^ # A carat symbol
\/ # A slash
\\ # A backslash
and so on.


Some example REs

As was mentioned earlier, it's probably best to build up your use of regular expressions slowly. Here are a few examples. Remember that to use them for matching they should be put in /.../ slashes
[01]  # Either "0" or "1"
\/0 # A division by zero: "/0"
\/ 0 # A division by zero with a space: "/ 0"
\/\s0 # A division by zero with a whitespace:
# "/ 0" where the space may be a tab etc.
\/ *0 # A division by zero with possibly some
# spaces: "/0" or "/ 0" or "/ 0" etc.
\/\s*0 # A division by zero with possibly some
# whitespace.
\/\s*0\.0* # As the previous one, but with decimal
# point and maybe some 0s after it. Accepts
# "/0." and "/0.0" and "/0.00" etc and
# "/ 0." and "/ 0.0" and "/ 0.00" etc.

【下列文章您可能也有興趣】

沒有留言: