网站首页 > 技术文章 正文
一、使用字符组代替分支条件
eg. 使用[a-d]表示a~d之间的字母,而不是使用(a|b|c|d)
function regTest($pattern,$str,$cnt){
$start=microtime(true);
for ($i=0;$i<$cnt;$i++){
preg_match($pattern,$str);
}
echo 'waste time(s): ',number_format(microtime(true)-$start, 10),'<br>';
}
$cnt=15;//最好设大数,eg.1000
$str='';
for ($i=0;$i<$cnt;$i++){
$str.='abababcdefg';
}
//方案1:分支条件
regTest("/^(a|b|c|d|e|f|g)+$/",$str,$cnt);
//方案2:字符组
regTest("/^[a-g]+$/",$str,$cnt);
//方案3:同方案2
regTest("/^[abcdefg]+$/",$str,$cnt);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
可以看出使用字符组比使用分支条件速度快很多。这是由于在匹配单个字符的时候,引擎会把[abc]这样的字符组视为一个元素,而不是3个元素(a、b、c)。整个元素作为匹配迭代的一个单元,不需要进行三次迭代,从而提高匹配效率。
二、优化选择最左端的匹配结果
对于传统NFA引擎来说,因为引擎一旦找到匹配结果就会停下来,而不会去尝试正则表达式的每一种可能(PHP中的preg函数就属于传统型NFA引擎)。
三、标准量词是匹配优先的
若用量词约束某个表达式,那么在匹配成功前,进行的尝试次数有下限和上限。eg.
preg_match('/\w*(\d+)/','copy2003y',$match);
- 1
这条正则表达式匹配的$1结果应该是3。解释如下:当正则引擎用“\w*(\d+)”匹配字符串copy2003y时,会先用“\w*”匹配字符串copy2003y。而“\w*”会匹配字符串copy2003y的所有字符,然后再交给“\d+”匹配剩下的字符串,而剩下的没有了。这时,“\w*”规则会不情愿地吐出一个字符,给“\d+”匹配。同时,在吐出字符之前,记录一个点,这个点就是用于回溯的点。然后“\d+”匹配y,发现不能匹配成功,此时会要求“\w*”再吐出一个字符;“\w*”先记录一个回溯的点,再吐出一个字符。这时,“\w*”匹配结果只有copy200,已经吐出3y。“\d+”再去匹配3,发现匹配成功,会通知引擎,并且直接显示出来。所以,“(\d+)”的结果是3,而不是2003。
如果改为非贪婪模式呢?“\w*?(\d+)”匹配的结果就应该是2003。由于“\w*?”是非贪婪,正则引擎会用表达式“\w*?”每次仅匹配一个字符串,然后再将控制权交给后面的“(\d+)”匹配下一个字符,同时记录一个点,用于匹配不成功时,返回这里再次匹配。
尽量以组为单位进行匹配,使用固话分组就能避免无休止的匹配。
四、谨慎用点号元字符,尽可能不用星号和加号这样的任意量词
只要能确定范围(eg.“\w”),就不要用点号;只要能够预测重复次数,就不要用量词。假设一条微博消息的XML正文部分结构如下:
<span class="msg">...</span>
- 1
正文中无尖括号,写法如下:
<span class="msg">[^<]{1,200}</span>
- 1
或者:
<span class="msg">.*</span>
- 1
上述第一种代码的思路要好于第二种,原因如下:
1、使用“[^<]”,保证了文本的范围不会超过下一个小于号所在位置
2、明确长度范围{1,200},依据是一条微博消息大致的字符长度范围是固定的,现在微博字数长度限制是140个字。
同时,能使用懒惰匹配就坚决不用贪婪匹配。
五、尽量使用字符串函数处理代替
使用字符串函数和正则表达式都可以处理字符串,两者相比,字符串函数处理的效率更高。当然,有些情况几乎是非正则表达式不能胜任的,或者不用正则表达式的成本太高,这些情况不得不用正则表达式。
六、合理使用括号
每使用一个普通括号(),而不是非捕获型括号(?:),就会保留一部分内存等着再次访问。
七、起始、行描点优化
能确定起止位置,使用^能提高匹配的速度。同理,使用$标记结尾,正则引擎则会从符合条件的长度处开始匹配,略过目标字符串中许多可能的字符。在写正则表达式时,应该将描点独立出来,例如“^(?:abc|123)”比“^123|^abc”效率高,而“^(abc)”比“(^abc)”效率更高。
这个原则不适用于所有正则引擎。比如在PCRE中,二者效率相当。
八、量词等价转换的效率差异
例如在PHP中,使用“\d\d\d”和“\d{3}”,或者“====”和“={4}”,它们之间的效率几乎没有差别。但是使用其他语言可能就会有比较明显的性能差异了。
九、对大而全的表达式进行拆分
十、使用正则以外的解决方案
eg.
1、 同五;
2、在某项目需要分析PHP代码,分离出对应的函数调用(以及源代码对应的位置)。虽然这些正则表达式也可以实现,但无论从效率还是代码复杂度方面考虑,这都不是最有方法。PHP已经内置解析器的接口PHP Tokenizer。使用PHP Tokenizer能简单、高效、准确地分析出PHP源代码的组成;
3、在解析URL时没必要使用正则表达式,使用parse_url函数即可;
4、在获取HTTP头时,也可以使用get_headers函数;
5、在进行输入校验时,可以使用filter_var函数,如:
filter_var($email,FILTER_VALIDATE_EMAIL);
- 1
6、如果在JavaScript里,可以使用DOM代替一些正则匹配。
- 上一篇: 系统化学习,第16节:二极管好坏判定
- 下一篇: 样品光电流吸收系数测量的实验设置和方法
猜你喜欢
- 2024-10-27 样品光电流吸收系数测量的实验设置和方法
- 2024-10-27 中级|软考题库每日一练|3.19 中级软考历年真题
- 2024-10-27 系统化学习,第16节:二极管好坏判定
- 2024-10-27 定形,定性,定量——2022年湖州中考数学第24题
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)