PHP正则效率与PHP字符串效率对比 测试例子(1)

作者:enenba | 发表于:2012-04-21 22:48 | 分类:正则表达式

     这次研究PHP正则效率与PHP字符串问题,很多时候我们都使用正则,当然讨论用PHP正则表达式的弊端也比较多,PHP正则表达式是不是真的很不效率,EnEnba开始上例子来看看,数据决定一切。

测试环境:XP+Apache2.2.6 +PHP5.2.17

 

    例子很简单,就是匹配hao123.com首页的<title>标签内容。hao123.com的源码下载至本地文件为hao123.html。为了体现公平,从得到字符串开始 记时开始,匹配100次后结束。

以下的正则和字符串操作都能正确匹配出结果。

 

测试源码1:
贪婪型的正则,这个是网上最多的正则

<?php
$str = file_get_contents('hao123.html');
define('START_TIME',microtime(true));
for($n=1;$n<=100;$n++) {
	preg_match('#<title>(.*)</title>#is',$str,$r);
}
//echo $r[1];
echo (microtime(true) - START_TIME).'s'; 
?>

 

测试源码2:
非贪婪型的正则、这是贪婪型的优化版

<?php
$str = file_get_contents('hao123.html');
define('START_TIME',microtime(true));
for($n=1;$n<=100;$n++) {
	preg_match('#<title>(.*?)</title>#is',$str,$r);
}
//echo $r[1];
echo (microtime(true) - START_TIME).'s'; 
?>

 

测试源码3:
无回溯的正则,这算是此正则的最优版

<?php
$str = file_get_contents('hao123.html');
define('START_TIME',microtime(true));
for($n=1;$n<=100;$n++) {
	preg_match('#<title>([^<]*)</title>#is',$str,$r);
}
//echo $r[1]
echo (microtime(true) - START_TIME).'s'; 
?>

 

测试源码4:
字符串操作,对比使用正则有什么优势。 

<?php
$str = file_get_contents('hao123.html');
define('START_TIME',microtime(true));
for($n=1;$n<=100;$n++) {
	$start = stripos($str,'<title>')+7;
	$length = stripos($str,'</title>')-$start;
	$r = substr($str,$start,$length);
}
//echo $r;
echo (microtime(true) - START_TIME).'s'; 
?>

 

 

100次循环用时结果:

一、测试源码1:贪婪型的正则
用时:
 1.84824609756s
 1.81924510002s
 1.83465003967s
 1.82647705078s
 1.83154320717s
 1.81038379669s
 1.80642414093s
 1.81480193138s
 1.81055712700s
 1.82441902161s

 

二、测试源码2:非贪婪型的正则
 0.00148916244507s
 0.00124597549438s
 0.00130200386047s
 0.00129199028015s
 0.00134801864624s
 0.00129318237305s
 0.00124812126160s
 0.00129103660583s
 0.00125002861023s
 0.00144720077515s
 0.00070405006408s

 

三、测试源码3:无回溯的正则
 0.000961065292358s
 0.000746965408325s
 0.000747203826904s
 0.000746011734009s
 0.000751018524170s
 0.000831127166748s
 0.000749111175537s
 0.000746011734009s
 0.000929832458496s
 0.000748157501221s
 0.000812053680420s

 

四、测试源码4:字符串操作
 0.561131954193s
 0.558562994003s
 0.554402112961s
 0.558073997498s
 0.558518171310s
 0.560245990753s
 0.557929992676s
 0.559715986252s
 0.560138940811s
 0.556318998337s
 0.558421134949s

 

10次结果平均用时:(时间越短效率越高)
一、测试源码1:贪婪型的正则
1.82267475128s

 

二、测试源码2:非贪婪型的正则
0.00139107704s

三、测试源码3:无回溯的正则
0.00087685585s 

 

四、测试源码4:字符串操作
0.56434602737s

 

此例子结果
效率:无回溯的正则 > 非贪婪型的正则 > 字符串操作 > 贪婪型的正则

 

与字符串操作的效率倍数
贪婪型的正则0.33倍  非贪婪型的正则400倍  无回溯的正则700

最好最坏成绩相差2000倍!!!!

     从此例子的结果可以看出,正则的效率是参差不齐。回溯较多的贪婪型的正则表达式,效率非常低,低于字符串操作,字符串操作上看,却远远低于非贪婪和无回溯的正则,已经不是一个数量级。无回溯的正则是非贪婪型的正则的1.75倍,也是非常明显的。

 

博主结论:正则表达式的效率不一定比字符函数的效率低。但是可以肯定的是正则表达式的优化做得不好的话,其效率可以是天壤之别。所以,正则表达式是可以使用的,但一定要减少正则的回溯,优化正则表达式是必须的。

 

enenba.com 原创正则文章,转载请注明出处 http://enenba.com/?post=143 

end

附件下载/演示源码:
regtest.rar18.24KB

上一篇: php正则去掉img标签中的 border属性   |   下一篇:php验证时间格式,只有年月日» 标签: 正则 正则表达式 正则效率

评论:

2012-07-03 20:23

这篇文章反复拜读,本地测试过很多遍.
想请教下:
1.'#<title>([^<]*)</title>#is'  中具体的原理,匹配到符号"<"后面的*,会回溯一次检查这个<么?

2.我使用的是字母,发现可以正确匹配,如下:/<b href=([^(ABC)]*)ABC<\/b>/
可以匹配这样的标签 匹配这样的标签 :<b href="xxxxx">ABC</b>
但中文失败,比如:无法匹配 <b href="xxxxx">中文</a> ,可有解法?

//竟然不让A标签..

2012-07-05 14:41

1、“[^<]*”取得控制权后,由于“*”是匹配优先量词,优先尝试右匹配直到匹配失败,当遇到“<”时“[^<]*”匹配失败,控制权交给正则表达式的“</title>”,“</title>”也能顺利匹配 。所以不会回溯检查“<”的。
2、/<b href=([^(ABC)]*)ABC<\/b>/  我不太清楚你写的这个要实现什么功能,我就你写的这个表达式的意思匹配《a>标签,并且链接href=后部内容不能包含“ABC”,并且以ABC连接名结尾,匹配形如:“ <ahref=...ABC</a>”的内容,并且“...”中不能包含“ABC”   。
所以
“<a href="xxxxx">ABC</a>”可以匹配;
“<a href="xxxxx">中文</a>”不能匹配。
具体解法我先理解你想要才写出