※ [本文转录自 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