美文网首页
PHP正则 "?" 使用

PHP正则 "?" 使用

作者: 爱折腾的傻小子 | 来源:发表于2018-11-29 15:04 被阅读9次
    php 中贪婪匹配 与 惰性匹配
    • 贪婪匹配:尽可能多的匹配多的字符

      • 比如 正则表达式 "m.*n" 它将匹配最长以m开始,n结尾的字符串。
      • 如果用它来搜索manmpndegenc的话,它将匹配到的字符串是manmpndegen而非man。
      • 可以这样想,当匹配到m的时候,它将从后面往前匹配字符n。
      • 贪婪匹配 尽可能匹配多字符
    • 惰性匹配:尽可能少的匹配字符

      • 将一个贪婪匹配转为惰性匹配呢?只需要在其后面添加一个"?"即可
      • 如"m.*?n"将匹配manmpndegenc,匹配到的字符串是man。
    • 示例

        /*
         * preg_match 执行一个正则表达式匹配
         * int preg_match(string $pattern, string $subject [, array &$matches [, int $flags = 0, int $offset = 0]])
         * $pattern 要搜索的模式
         * $subject 输入字符串
         * $matches 搜索结果 $matches[0]将包含完整模式匹配到的文本 $matches[1]将包含第一个捕获子组匹配到的文本
         * $flags   标记:PREG_OFFSET_CAPTURE 如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。
         *          注意:这会改变填充到matches参数的数组,
         *          使其每个元素成为一个由第0个元素是匹配到的字符串,
         *          第1个元素是该匹配字符串在目标字符串subject中的偏移量
         * $offset  搜索从目标字符串的开始位置开始。指定从目标字符串的某个未知开始搜索(单位是字节)
         */
    
        $m = array();
        $string = "manmpndegenc";
        // 贪婪模式
        preg_match("|m.*n|",$string,$m);    // $m => [0 => "manmpndegen"]
       // 惰性模式
        preg_match("|m.*?n|",$string,$m);   // $m => [0 => "man"]
    
        dump($m);
    
    函数符 描述
    *? 零次或多次,但尽可能少的匹配
    +? 一次或多次,但尽可能少的匹配
    ?? 零次或壹次,但尽可能少的匹配
    {n,}? 至少n次,但尽可能少的匹配
    {n,m}? n到m次,但尽可能少的匹配
    php正则表达式 回溯与固态分布
    回溯
    • 回溯就像是在走岔路口,当遇到岔路的时候就先在每个路口做一个标记。
    • 如果走了死路,就可以照原路返回,直到遇见之前所做过的标记,标记着还未尝试过的道路。
    • 如果那条路也走不能,可以继续返回,找到下一个标记,如此重复,直到找到出路,或者直到完成所有没有尝试过的路。
    $str='aageacwgewcaw';
    $pattern='/a\w*c/i';
    $str=preg_match($pattern, $str);
    
    // 匹配$str是否包含这样一个由”a+0个或多个字母+c”不区分大小写的字符串。
    // 但是至于程序怎样去匹配的呢?匹配的过程中,回溯了多少次呢?
    
        $mat = array();
        // \w 匹配 字母(大写/小写)数字下划线
        $str='aageacwgewcaw';
        $pattern='/a\w*c/i';
        // aageac       惰性匹配
        // aageacwgewc  贪婪匹配
        preg_match($pattern, $str, $mat);
    
        /*
         * array:1 [
         *  0 => "aageacwgewc"
         * ]
         */
        dump($mat);
    
    匹配过程 接下来操作描述
    "a\w*c"中a匹配到"aageacwgewcaw"中第一个字符a \w进行下一个字符匹配
    \w是贪婪匹配,会一直匹配到"aageacwgewcaw"中最后一个字符w c进行下一个字符匹配时
    "a\w*c"中c发现没有可以匹配的 于是\w匹配进行第一次回溯,匹配到倒数第二个字符a
    "a\w*c"中c发现还是没有可以匹配的 于是\w匹配进行第二次回溯,匹配到倒数第三个字符c
    "a\w*c"中c匹配成功 匹配介绍返回结果
    • 如果我们将pattern改为pattern="/a\w*?c/i";又会回溯多少次呢?正确答案是回溯三次。
    • 匹配过程 "aageacwgewcaw"
    匹配过程 备注 下部操作
    "a\w*?c" => aag 匹配失败 回溯到 "aa" \w => ag
    "a\w*?c" => aage 匹配失败 回溯到 "aag" \w => age
    "a\w*?c" => aagea 匹配失败 回溯到 "aage" \w => agea
    "a\w*?c" => aageac 匹配成功 ---- ----
    固态分组
    • 固态分组:减少回溯次数 (注意下面加粗字符)
    • 使用(?>...)括号中的匹配如果产生了备选状态,那么一旦离开括号便会被立即 引擎抛弃掉。
    • 例子:
      • \w+:’这个表达式在进行匹配时的流程是这样的,会优先去匹配所有的符合\w的字符。
      • 假如字符串的末尾没有’:’,即匹配没有找到冒号,此时触发回溯机制,他会迫使前面的\w+释放字符,并且在交还的字符中重新尝试与’:’作比对。
      • 但是问题出现在这里: \w是不包含冒号的,显然无论如何都不会匹配成功,可是依照回溯机制,引擎还是得硬着头皮往前找,这就是对资源的浪费。
      • 所以我们就需要避免这种回溯,对此的方法就是将前面匹配到的内容固化,不令其存储备用状态!,那么引擎就会因为没有备用状态可用而只得结束匹配过程。大大减少回溯的次数。
      • 备注 \w 匹配 字母(大小写)数字下划线
        $m = array();
    
        $str = "nihaoaheloo";
        $pattern = "/(?>\w+):/";
    
        preg_match($pattern, $str, $m);
    
        // []
        dump($m);
    
    • 当然有些时候,又需慎用固态分组,如下,我要检查$str中是否包含以a结尾的字符串,很明显是包含的,但是因为使用了固态分组,反而达不到我们想要的效果。
    $str='nihaoahelaa';
    $pattern1='/(?>\w+)a/';
    $pattern2='/\w+a/';
    $rs=preg_match($pattern1, $str);//0
    $rs=preg_match($pattern2, $str);//1
    
    php 正则 (?:pattern) 作用
    $rule1 = "/(?:\w+)/";   // 匹配,则捕获整体,不会捕获子组
    $rule2 = "/(\w+)/";     // 匹配,则捕获整体,并捕获子组
    
    preg_match($rule1, "Hi", $matches);
    preg_match($rule2, "Hi", $matches2);
    
    /**
    * array:1 [
    *  0 => "Hi"
    * ]
    */
    dump($matches);
    
    /**
    * array:2 [
    *  0 => "Hi"
    *  1 => "Hi"
    * ]
    */
    dump($matches2);
    
    • 作用: (|) 来组合一个模式有用,如, 'industr(?:y|ies) 就是一个比 'industry|industries' 更简略的表达式。

    参考文档:
    php中正则表达式详解 | 作者:helloworldlee | 链接:https://www.cnblogs.com/hellohell/p/5718319.html

    相关文章

      网友评论

          本文标题:PHP正则 "?" 使用

          本文链接:https://www.haomeiwen.com/subject/sqixcqtx.html