正则表达式惰性量词断言开始和结束

Regex lazy quantifier asserted beginning and end

当将正则表达式量化为惰性时,例如 \w{2,4}?,当断言为测试的开始和结束时,它是否比其他方式(贪婪)更有效或更不有效?

例如^\w{2,4}?$ 对比 ^\w{2,4}$ 测试 '12345' '1234'

两者都不匹配您的测试字符串,因为您的输入包含 5 个字符,而您的正则表达式仅匹配具有 2 到 4 个字符的字符串。使用锚点时不需要此 ?^.*?$^.*$ 的作用相同。我建议您使用 ^\w{2,4}$ 而不是 ^\w{2,4}?$。第二个需要 8 个步骤才能找到匹配项,而第一个需要 5 个步骤才能找到匹配项。

DEMO

让我们将 1234 视为示例字符串。

  1. ^\w{2,4}$

    从一开始,上面的正则表达式会贪婪地匹配范围从 2 到 4 个字符的所有字符,并且 $ 锚断言我们在最后。

  2. ^\w{2,4}?$

    但是当我们使用它时,它最多匹配两个字符并检查行尾。因为第二个字符旁边没有行尾锚点,所以它匹配第三个字符并再次检查第三个字符旁边的行尾锚点。结果是否定的,所以它移动到下一个字符并匹配它。现在它检查线锚的末端。是的,这是行尾。如果它在第四个字符之后有任何字符,那么它会放弃它的操作。这就是步数比贪心步数多的原因。

否。贪婪量词和惰性量词都会创建 "backtracks".

但是,possessive quantifier "+" 不会创建回溯,因此在某些情况下速度更快。它确实有一个非常特殊的行为,并且有许多不支持所有格量​​词的正则表达式引擎(javascript 不支持,PCRE 支持)

Avinash Raj 所述,回溯将不会在这个特定示例中使用,所有这些表达式

^\w{2,5}?$ ^\w{2,5}$ ^\w{2,5}+$ ^\w{2,4}?$ ^\w{2,4}$ ^\w{2,4}+$

匹配字符串12345的时间不会有区别

参见 答案。

<?php header('Content-Type: text/plain');
$s = str_repeat("12345\n",1000);
function a($r){
    global $s;
    $r = '#'.$r.'#m';
    $time_a = (double)microtime(true);
    for($i=0;$i<100000;$i++)preg_match( $r, $s );
    echo "$r\t".( (double)microtime(true) - $time_a )."\n";
}
a('^\w{2,5}$');  // 0.093012094497681 ; 0.10101294517517 
a('^\w{2,5}?$'); // 0.095011949539185 ; 0.09201192855835 
a('^\w{2,5}+$'); // 0.094011783599854 ; 0.093512058258057
a('^\w{2,4}$');  // 4.3395512104034   ; 4.3435509204865    
a('^\w{2,4}?$'); // 4.3420507907867   ; 4.3610541820526    
a('^\w{2,4}+$'); // 4.3565537929535   ; 4.353052854538     
// lazy "?" quantifier is slower than greedy