本文是阅读老姚的《JavaScript正则表达式迷你书》后笔记,强烈建议学习,花个周末便可学完。
正则表达式是匹配模式,要么匹配字符,要么匹配位置
字符匹配
贪婪匹配与惰性匹配:
{}、?、+、*默认是贪婪匹配,会匹配最多- 惰性匹配为
{}、?、+、*后加?,会匹配最少
例,利用惰性匹配匹配id<div id="divId" class="divClass"></div>
'<div id="divId" class="divClass"></div>'.match(/id=".*?"/)
去掉?会贪婪匹配class中最后一个"。但是上面方法性能比较低,因为存在回溯,即从i开始每次都要先检查",可以优化成/id="[^"]*"/
位置匹配(同一位置可以匹配多次)
^匹配第一个字符前的位置$匹配最后一个字符后的位置\b匹配\w的前后位置\B匹配非\b的其它位置?=表达式 匹配表达式前的位置。?!表达式 表示无法匹配表达式前的位置,即没有该表达式 例,匹配密码,6-12位,包含大写字母、小写字母、数字,且至少包含两种类型 解法一,包含解法
- 先不管包含两种类型
/^[0-9a-zA-Z]{6,12}$/ - 至少包含数字
/(?=.*[0-9])^[0-9a-zA-Z]{6,12}$/->?=.*[0-9]匹配第一个字符前面的位置 - 至少包含数字和小写字母
/(?=.*[0-9])(?=.*[a-z])^[0-9a-zA-Z]{6,12}$/ - 加上另外两种可能,即可以用|匹配 解法二,排除法,即不能只包含一种
- 不能只包含数字
/(?!^\d*$)^[0-9a-zA-Z]{6,12}$/ - 加上另外两种可能,即可以用|匹配
例,将每个单词首字母大写
str.(/\b\w/g, s => s.toUpperCase())
- ?<=表达式,匹配表达式后面的位置,记忆:<=看成是箭头,?看成是位置,及?左边是表达式。?<!表达式,与?<=相反
括号
- 与
|配合表示分支 - 分组引用
'abab cd'.match(/(ab)+/)得到的结果是['abab', 'ab'],第二个参数开始,如果有括号,则对匹配到的结果,按括号顺序,将最后一个括号内匹配到的接口列出来。例如'12345'.match(/(\d)+/)为['12345', '5']。同时可以对括号匹配到的值赋值给$n,n->1-99 - 反向引用:用
\n(n->1-99)匹配之前括号匹配到的值,例如/\d{4}(-|\/|\.)\d{2}\1\d{2}/即可匹配2021-12-12,而无法匹配2021/12-12 - 取消捕获:如果括号内只是由于逻辑原因加的括号,并且不想被捕获,使用
(?:表达式)即可
回溯
当前子匹配规则匹配中无法选中,需回溯到上一匹配,然后再使用下一规则
例:/ab{1,3}bbc/.test('abbbc'),匹配结果为true,但匹配过程是ab{1,3}匹配abbb,然后匹配c的时候发现匹配失败,则会回溯。由此可见,回溯会影响匹配效率。
存在回溯情况
- 贪婪匹配 不足时越前匹配越多
- 惰性匹配 超出时越前匹配越多
- 分支匹配
编写正则表达式注意事项
- 先确定是否需要正则,因为可能js判断会更简便。是否需要一个复杂的正则,可以简化成多步来判断
- 先保证准确性再优化性能
- 减少回溯
习题
- 逗号分隔数字,例
123123123 -> 123,123,123
// 从$结尾开始算,每三个数字加一个逗号,再排出开始位置
number.replace(/(?=\B\d{3}+$)/g, ',')
- 转小驼峰,例
ab_cd_ef -> abCdEf、ab-cd-ef -> abCdEf
str.replace(/[_-]\w/g, e => e.toUpperCase())
- 转全小写,以
-间隔,例abCdEf -> ab-cd-ef
str.replace(/\B([A-Z])/g, '-$1').toLowerCase()
- 判断颜,例
#fff、#ffffff
/^#([0-9a-zA-Z]{3}|[0-9a-zA-Z]{6})$/.test(str)
- 提取html字符串中所有图片
var list = []
document.body.innerHTML.replace(/<img[^>]*?src="([^"]*)"/g, (_, s) => list.push(s))