PHP正则 "?" 使用

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正则 "?" 使用)