欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

PHP正则式PCRE

程序员文章站 2022-07-02 17:04:19
1)cat(arcat|erpillar|)匹配 ”cat”, “cataract”, “caterpillar” 中的一个。 2)一次性子组(非捕获子组)和后瞻断言结合使用来指定在目标字符串末尾的有效匹配,比如^(?>.*)(?<=abcd)相对于^.*abcd$更为高效。 3)条件子组(非捕获子... ......

PHP正则式PCRE的总结差不多就下边这些了。参考 PCRE与perl的差异 

 

锚(^、$、\A、\Z/\z)

在多行模式下是非紧固的,在单行模式下是紧固的;而\A、\Z / \z在任何模式下都是紧固的(\G表示在目标中首次匹配位置,还可以与$offset参数一起使用)。

 

断言

一个断言指定一个必须在特定位置匹配的条件,它们不会从目标字符串中消耗任何字符,因此也不会出现在结果中。一个断言子组以前瞻断言“(?=)”或“(?!)”、后瞻断言“(?<=)”或“(?<!)”形式出现:

(1)\b指单词边界(\b在字符类中表示退格backspace字符),\B指非单词边界。
(2)当字符串结束字符为换行符时,\Z 会将其看做字符串结尾匹配, 而 \z 只匹配字符串结尾。
(3)前瞻断言(?!foo)bar会查找到任意的barxxxxx而非foo跟随bar的情况。
(4)后瞻断言的内容被严格限制为只能用于匹配定长字符串,比如 (?<=bullock|donkey) 是允许的,但是 (?<!dogs?|cats?)、 (?<=ab(c|de)) 将会引发一个编译期的错误。
(5)多个断言(任意顺序)可以同时出现,如 (?<=\d{3})(?<!999)foo 匹配前面有三个数字但不是 ”999” 的字符串 ”foo”。
(6)断言可以以任意复杂度嵌套,比如 (?<=(?<!foo)bar)baz 匹配前面有 ”bar” 但是 ”bar” 前面没有 ”foo” 的 ”baz”, 另外(?<=\d{3}…(?<!999))foo 匹配前面有三个数字字符紧跟 3 个不是 999 的任意字符的 ”foo”。
(7)如果所有的断言都包含一个捕获子组,那么为了在整个模式中捕获子组计数的目的,它们都会被计算在内;然而子字符串的捕获仅可以用于正面断言,因为对于消极的断言是没有意义的。

  

内部选项(?)

如果一个选项在子组内部设置,仅仅改变子组中剩余的部分,因此 (a(?i)b)c 仅仅匹配 ”abc” 和 ”aBc” (假设没有使用 PCRE_CASELESS 选项);但在同一个子模式中, 一个分支的内部选项设置会穿透到后面的其他分支中去,比如 (a(?i)b|c) 匹配”ab”或“aB”或“c”或”C”(选项是在编译期确定下来的,在匹配 ”C” 时第一个分支已被丢弃)。

 

模式修饰符

主要有i(PCRE_CASELESS)、m(PCRE_MULTILINE)、s(PCRE_DOTALL)、x(PCRE_EXTENDED)、A(PCRE_ANCHORED)、D(PCRE_DOLLAR_ENDONLY)、U(PCRE_UNGREEDY)等。模式修饰符中的空格、换行符会被忽略,其他字符会导致错误。

 

子组/子模式与分支(|)

子组通过圆括号(其作用是局部化和捕获子组,而“(?:)”不捕获子组,“(?|)”使可多个分支复用一个后向引用编号)来分隔界定,并且它们可以嵌套:

(1)cat(arcat|erpillar|)匹配 ”cat”, “cataract”, “caterpillar” 中的一个。
(2)一次性子组(非捕获子组)和后瞻断言结合使用来指定在目标字符串末尾的有效匹配,比如^(?>.*)(?<=abcd)相对于^.*abcd$更为高效。
(3)条件子组(非捕获子组)型如(?(condition)yes-pattern)、(?(condition)yes-pattern|no-pattern),condition是数字(后向引用某个捕捉子组)或字串或断言。(\()?[^()]+(?(1)\))匹配一个没有括号的或者闭合括号包裹的字符序列。
(4)命名子组(捕获子组)形如 (?P<name>pattern)、(?<name>pattern)、(?’name’pattern),可通过(?P>name)、(?P&name)形式在模式中再次引用命名子组,但这种引用不可捕获。

 

字符类与转义字符

字符类\d、\D、 \s、\S、\w 和 \W 也可以出现在一个字符类中, 用以将其匹配的字符类加入到新的自定义字符类中。比如, [\dABCDEF] 匹配任意合法的 16 进制数, [^\W_] 匹配任何字母或数字但不匹配下划线。\Q 和 \E 可忽略正则表达式元字符,

\w+\Q.$.\E$ 

该模式会匹配一个或多个单词字符,紧接着一个点号,一个$,一个点号, 最后锚向字符串末尾;\K 可以用于重置匹配,比如 foot\Kbar 匹配”footbar”,但是得到的匹配结果是 ”bar”。

 

注释

模式中形如“(?# comments)”的部分表示注释内容。如果设置了 PCRE_EXTENDED 选项, 一个字符类外部的未转义的 # 字符就代表本行剩余部分为注释。

 

递归模式(?R) 

(?R) 提供了递归的这种特殊用法,如

\(((?>[^()]+)|(?R))*\)

该模式可匹配字串(ab(cd)ef)。

 

分隔符

分隔符可以使任意非字母数字、非反斜线、非空白字符,如正斜线(/)、hash符号(#)、取反符号(~)等。

 

后向引用

(?1)、(?2)、(?P>name)、(?P&name)、(?P=name)、\1、\k<name>、\k’name’、\k{name}、\g{name}等形式可以用于引用之前定义的子组。需注意,\n复用匹配结果,而(?n)、(?P>name)、(?P&name)复用模式。(a|(bc))\2 总是在匹配 ”a” 开头而不是 ”bc” 开头的字符串时失败,故可以换成(a|(bc))(?2)。对后向引用后有数字可以空格分隔并使用x修饰符,或使用\g{n}这种格式(序列\1, \g1,\g{1}之间是同义关系),(foo)(bar)\g{-1} 可以匹配字符串 ”foobarbar”。子组内部后向引用自己(a\1)会失败,但(a|b\1)*遇到aba会成功;也就是模式在第一次迭代的时候,必须能够保证不需要匹配后向引用。

 

PCRE不允许前瞻断言的量词修饰

(?!a){3}并不意味着接下来 3 个字符不是 a,而是断言下一个字符不是 a 并进行了 3 次断言。

 

//verify email address
//$match: Array ( [0] => w12aqe_@124afasf.com [1] => 124afasf. )
$patt = '/^(?!_|-)(?>[\w-]+)@(?!-)(?>((?>[a-zA-Z0-9-]+)\.)+)[a-zA-Z]{2,46}$/';
preg_match($patt,'w12aqe_@124afasf.com',$match);

//$match: Array ( [0] => Sunday [day] => Sunday [1] => Sunday )
$patt = '/(?<day>:(?i)saturday|sunday)/';
preg_match($patt,'Sunday',$match);

//$match: Array ( [0] => Sunday [1] => Sun )
$patt = '/(?|(Sat)ur|(Sun))day/';
preg_match($patt,'Sunday',$match);

//子组发生重复多次匹配时,捕获的是最新一次的值
//$match: Array ( [0] => (ab(cd)ef) [1] => ab(cd)ef [2] => ef )
$patt = '/\( ( ( (?>[^()]+) | (?R) )* ) \)/x';
preg_match($patt,'(ab(cd)ef)',$match);

//命名子组可通过名称或序号来再次引用
//$match: Array ( [0] => 23ab45cd56 [number] => 23 [1] => 23 )
$patt = '/^(?P<number>\d+)ab(?P>number)cd(?1)$/';
preg_match($patt,'23ab45cd56',$match);

//下列模式相当于^.*abcd$
//$match: Array ( [0] => 23abcd )
$patt = '/^(?>.*)(?<=abcd)/';
preg_match($patt,'23abcd',$match);