精華區beta RegExp 關於我們 聯絡資訊
※ [本文轉錄自 PHP 看板 #1EaPVkLE ] 作者: knuckles (那克斯) 看板: PHP 標題: [分享] PHP官網對於RegExp小括弧()用法的說明 時間: Sun Oct 9 20:47:39 2011 PHP官網寫的好難懂,所以來整理一下自己的心得版 PHP官方網站對於 regular expression 的小括號 () 用法的說明頁 http://www.php.net/manual/en/regexp.reference.subpatterns.php 我自己寫的一點筆記: (網頁上色版 http://disp.cc/b/11.cj-1SO9 ) 小括弧有兩種用途: 1. 群組各種可能的子字串,例如 /filename\.(jpg|png|gif)/ 這樣就可以找到這三種副檔名的圖檔 2. 標記要取得的字串,例如 /a=(.*?)&b=(.*?)&c=(.*?)&d=/ 就可以把 a, b, c 的值分別存到 $1, $2, $3 這兩種用途有時候會混在一起,像是 preg_replace("/((red|white) (king|queen))/","$1, $2, $3","red queen"); ← red queen → $1 ← red → $2 ← queen → $3 會得到 red queen, red, queen 如果只想拿()當群組用,但不要被算進要抓的字串,可以在(後加上 ?:,例如 preg_replace("/((?:red|white) (king|queen))/","$1, $2","red queen"); 會得到 red queen, queen (第二個括弧的red不會被抓出來了) ?:中間可以加上選項,例如 i 是忽略大小寫 寫成 (?i:saturday|sunday) 等同於 (?:(?i)saturday|sunday) 可以符合 SUNDAY 或 Saturday,i的效果僅限於這個() 抓到的字串,除了自動依順序配給 $數字 外,也可以自己加上名字 語法 (?P<name>pattern) ,在 PHP5.2.2 另外提供了 (?<name>pattern) 及 (?'name'pattern) 兩種用法 在當群組用時,若每個可能的字串又有用到標記要抓的字串時 例如 (?:(Sat)ur|(Sun))day 用在 Sunday 時,$1="",$2="Sun" 用在 Saturday 時,$1="Sat,$2不存在 此時可以改用 (?|(Sat)ur|(Sun))day 這樣就只會抓到1個字串,$1="Sun" 或 $1="Sat" 至於(?=)、(?!)、(?<=)、(?<!) 是 assertions 的用法 PHP官方網站對於 assertions 的說明 http://www.php.net/manual/en/regexp.reference.assertions.php 我寫的一點筆記: (網頁上色版:http://disp.cc/b/11.cj-2pRT ) Assertion 用來表達位置的符號,不會吃掉字元 例如 ^ : 符合整個字串的開頭;在multiline模式,代表一行的開頭 $ : 符合整個字串的結尾;在multiline模式,代表一行的結尾 \b : 符合一個單字邊界(word boundary),一邊是\w一邊是\W \B : 符合一個非單字邊界,兩邊都是\w 或兩邊都是\W \A : 只符合整個字串的開頭 (不受multiline模式影響) \Z : 只符合整個字串的結尾,或是結尾換行前 (不受multiline模式影響) \z : 只符合整個字串的結尾 (不受multiline模式影響) \G : 若使用preg_match有設offset時,代表offset的位置,offset為0時就與\A相同 如果是要表達前後是否為某個字串,但不要把這字串抓進來的話,有分為 Lookahead 看後面 (?=abc) : 接下來必需是abc (?!abc) : 接下來不能是abc Lookbehind 看前面 (?<=abc) : 前面是接abc (?<!abc) : 前面不是接abc 舉例 \w+(?=;) 只會抓到後面有接;的\w+,但不會把;抓進來 foo(?!bar) 會抓到所有後面不是接bar的foo (?!foo)bar 錯誤用法,這樣所有的bar都會抓到 如果想要前面不是接foo的話,要用Lookbehide的用法 (?<!foo)bar 這樣才對,會抓到所有前面不是接foo的bar 可以使用(?<=bullock|donkey)來抓前面是bullock或donkey的字串 但要注意lookbehind的用法時,所有匹配的字串可以分別為不同長度, 但每個必需是固定的長度,例如 (?<!dogs?|cats?) 就不行 要匹配不同長的字串也僅至於最上層的分支, 像 (?<=abc|abde) 可以,但 (?<=ab(c|de)) 就不行 Assertions可以連續使用 例如 (?<=\d{3})(?<!999)foo 可以抓到前面是3個非999數字的foo 注意這兩個assertions都是檢查同一個位置,所以不會抓到前面接6個字元的foo 像 123abcfoo 的foo就不會被抓到,如果要抓像這樣的foo, 要用(?<=\d{3}...)(?<!999)foo Assertions可以巢狀使用 例如 (?<=(?<!foo)bar)baz 可以抓到 前面是 bar 且 bar 的前面不是 foo 的 baz 例如 (?<=\d{3}...(?<!999))foo 可以抓到 前面是 3個數字與3個非999字元 的foo -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 111.248.11.75 -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 111.248.11.75
PurpleCrow:good! 10/10 17:15
mars90226:最後一個範例有點不懂...(?<!999)不是要放在某字串之前? 10/11 22:48
(?<=\d{3}...(?<!999))foo 意思就是說 (?<!999)前面那三個點不可以是999 當然也可以改成 (?<=\d{3}...)(?<!999)foo 代表 foo前面不可以是999 這兩個是一樣的結果,舉這個例子就是要說兩種用法都可以吧 lookbehind不一定只能放在字串前,lookahead也不一定只能放字串後 例如 (?!foo)... 可以用來表示 ... 不可以是foo ※ 編輯: knuckles 來自: 111.248.0.200 (10/12 00:23)
mars90226:了解了!感謝分享! 10/14 20:37