往期回顾
正文内容
正则的构建需要考虑以下几点的平衡:
- 匹配预期的字符串
- 不匹配非预期的字符串
- 可读性和可维护性
- 效率
我们还需要考虑这么几个问题:
- 是否需要使用正则
如能使用其他 API 简单快速解决问题就不需要使用正则:
- 是否需要使用复杂正则
/(?!^[0-9]{6,12}$)(?!^[a-z]{6,12}$)(?!^[A-Z]{6,12}$)^[0-9A-Za-z]{6,12}$/
将这个正则拆分成多个小块,如下:
1. 准确性
即需要匹配到预期目标,且不匹配非预期的目标。
- 匹配固定电话
如需要匹配下面固定电话号码,可以分别写出对应正则:
055188888888 => /^0\d{2,3}[1-9]\d{6,7}$/ 0551-88888888 => /^0\d{2,3}-[1-9]\d{6,7}$/ (0551)88888888 => /^0\d{2,3}-[1-9]\d{6,7}$/
然后合并:
let r = /^0\d{2,3}[1-9]\d{6,7}$|^0\d{2,3}-[1-9]\d{6,7}$|^\(0\d{2,3}\)[1-9]\d{6,7}$/
然后提取公共部分:
let r = /^(0\d{2,3}|0\d{2,3}-|\(0\d{2,3}\))[1-9]\d{6,7}$/
再优化:
let r = /^(0\d{2,3}-?|\(0\d{2,3}\))[1-9]\d{6,7}$/
- 匹配浮点数
先确定,符号部分([+-])、整数部分(\d+)和小数部分(\.\d+)。
整理后:
2. 效率
正则表达式运行过程:
- 编译
- 设定起始位置
- 尝试匹配
- 若匹配失败则返回前一步重新匹配
- 返回匹配成功失败的结果
我们常常优化对 3 和 4 步进行优化:
- 使用具体字符组替代通配符,消除回溯
如 /"[^"]*"/ 代替 /".*?"/。
- 使用非捕获型分组
当不需要使用分组引用和反向引用时,此时可以使用非捕获分组。
如 /^[-]?(?:\d\.\d+|\d+|\.\d+)$/ 代替 /^[-]?(\d\.\d+|\d+|\.\d+)$/。
- 独立出确定字符
加快判断是否匹配失败,进而加快移位的速度。
如 /aa*/ 代替 /a+/。
- 提取分支公共部分
减少匹配过程中可消除的重复。
如 /^(?:abc|def)/ 代替 /^abc|^def/。
- 减少分支的数量,缩小它们的范围
如 /rea?d/ 代替 /red|read/。
本文暂时没有评论,来添加一个吧(●'◡'●)