• PHP正则式PCRE


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

     

    锚(^、$、A、/z)

     ^、$ 在多行模式(PCRE_MULTILINE)下构造非紧固模式,在单行模式(美元符号可匹配字符串尾部的一个换行符)下可构造紧固模式;而A、 / z只用于构造紧固模式(G表示在目标中首次匹配位置,还可以与$offset参数一起使用)。

    断言

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

    (1)指单词边界(在字符类中表示退格backspace字符),B指非单词边界。
    (2)当字符串结束字符为换行符时, 会将其看做字符串结尾匹配, 而 z 只匹配字符串结尾。
    (3)前瞻断言(?!foo)bar会查找到任意的barxxxxx而不是“非foo跟随bar”的情况。

    preg_match('/(?<!.cp).anlaa.com$/i','dboadmin.cp.anlaa.com',$match);//$match = []

    (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” 时第一个分支已被丢弃)。(?im) 设置表明多行大小写不敏感匹配, 而(?im-sx) 设置了 PCRE_CASELESS,PCRE_MULTILINE, 但是同时取消了 PCRE_DOTALL 和 PCRE_EXTENDED。 如果一个字母即出现在 - 之前, 也出现在 - 之后,这个选项被取消设置。

    模式修饰符

    主要有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)形式在模式中再次引用命名子组,但这种引用不可捕获。

    重复/量词

     

    * 等价于 {0,}
    + 等价于 {1,}
    ? 等价于 {0,1}

    默认情况下,量词都是”贪婪”的,也就是说, 它们会在不导致模式匹配失败的前提下,尽可能多的匹配字符(直到最大允许的匹配次数),如对C代码“/* first comment*/ not comment /*second comment*/”匹配注释使用下列模式会匹配到整个字符串;

    /*.**/

    然而,如果一个量词紧跟着一个 ?(?起到模式反转的作用,也就是说如果设置了 PCRE_UNGREEDY((?U),且对目标使用括号如((?U).+)),模式将反转为贪婪;而如果量词紧跟着一个+,表示任何情况下都使用贪婪模式,因此 .*?abc 匹配 ”aabc”, 但是 .*+abc 不匹配) 标记,它就会成为懒惰(非贪婪)模式, 只做尽可能少的匹配。 因此上述模式应该改成这样:

    /*.*?*/ 

    补充一下,在贪婪或懒惰模式下,都是在保证成功的条件下来控制匹配的重复次数最多(/.*a/取决于最后一个a所在的位置)或最少:

    //$match = Array ( [0] => 214sfsbbb )
    $patt = '/^w*b$/';
    preg_match($patt,'214sfsbbb',$match);
    
    //$match = Array ( [0] => 214sfsbbb )
    $patt = '/^w*?b$/';
    preg_match($patt,'214sfsbbb',$match);
    
    //$match = Array ( [0] => 214sfsbbb )
    $patt = '/^w*b/';
    preg_match($patt,'214sfsbbb',$match);
    
    //$match = Array ( [0] => 214sfsb )
    $patt = '/^w*?b/';
    preg_match($patt,'214sfsbbb',$match);
    
    $subject = 'Aaaaaa Bbb';
    $target = 0;
    //$subject = "0123456 7B8b9b10"
    $subject = preg_replace_callback_array(
        [
              '/a?/i' => function ($match) use (&$target) {
                            return $target++;
                       },
        ],
        $subject
    );

    字符类与转义字符

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

    w+Q.$.E$ 

    该模式会匹配一个或多个单词字符,紧接着一个点号,一个$,一个点号, 最后锚向字符串末尾;K 可以用于重置匹配,比如 footKbar 匹配”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)、(?P>name)、(?P&name)复用模式。(a|(bc))2 总是在匹配 ”a” 开头而不是 ”bc” 开头的字符串时失败,故可以换成(a|(bc))(?2)。对后向引用后有数字可以空格分隔并使用x修饰符,或使用g{n}这种格式(序列1, g1,g{1}之间是同义关系),(foo)(bar)g{-1} 可以匹配字符串 ”foobarbar”。子组内部后向引用自己(a1)会失败,但(a|b1)*遇到aba会成功;也就是模式在第一次迭代的时候,必须能够保证不需要匹配后向引用。

    $data = 'a { b { 1 } c { d { 2 } } }';
    preg_match('/a (?<R>{(?:[^{}]+|(?&R))*})/', $data, $m);
    var_dump($m);
    array(3) { 
        [0]=> string(27) "a { b { 1 } c { d { 2 } } }" 
        ["R"]=> string(25) "{ b { 1 } c { d { 2 } } }" 
        [1]=> string(25) "{ b { 1 } c { d { 2 } } }" 
    }

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

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

    //verify email address
    //$match: Array ( [0] => w12aq.e_@124afasf.com [1] => 124afasf. )
    $patt = '/^(?!_|-)(?>[w.-]+)@(?!-)(?>((?>[a-zA-Z0-9-]+).)+)[a-zA-Z]{2,46}$/';
    preg_match($patt,'w12aq.e_@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);
    
    //下列模式用于XML去空及压缩
    $package = '<?xml version="1.0" encoding="UTF-8"?>
    <PARAM>
        <DBID>35</DBID>
        <SEQUENCE>atgtca</SEQUENCE>
        <MAXNS>10</MAXNS>
        <MINIDENTITIES>90</MINIDENTITIES>
        <MAXEVALUE>10</MAXEVALUE>
        <USERNAME>ad m
        in</USERNAME>
        <PASSWORD>111111</PASSWORD>
        <TYPE>P</TYPE>
        <RETURN_TYPE></RETURN_TYPE>
    </PARAM>';
            
    
    // 去除空元素
    $package = preg_replace('/<(w+)[^>]*>s*</1>|<w+[^>]*/>/i', '', $package);
    // XML压缩
    $package = preg_replace('/(?<=>)s+(?=</?w+>)/i', '', $package);

    PCRE系统错误

    // 打印最近的PCRE错误,非0值表示发生错误
    var_dump(preg_last_error());
    
    // preg_last_error() == 2时,可能是回溯次数超出限制了,可修改最大回溯解决,但不可无限上调该设置以免消耗内存资源过大。默认 pcre.backtrack_limit = 1000000
    ini_set('pcre.backtrack_limit', 100000000);
  • 相关阅读:
    openwrt 相关文章
    负载均衡相关文章
    Today's Progress
    Rodrigues formula is beautiful, but uneven to sine and cosine. (zz Berkeley's Page)
    Camera Calibration in detail
    Fundamental Matrix in Epipolar
    Camera Calibration's fx and fy do Cares in SLAM
    FilterEngine::apply
    FilterEngine 类解析——OpenCV图像滤波核心引擎(zz)
    gaussBlur
  • 原文地址:https://www.cnblogs.com/XiongMaoMengNan/p/8371350.html
Copyright © 2020-2023  润新知