js正则表达式学习笔记

573 阅读1分钟

本文是阅读老姚的《JavaScript正则表达式迷你书》后笔记,强烈建议学习,花个周末便可学完。

正则表达式是匹配模式,要么匹配字符,要么匹配位置

字符匹配

贪婪匹配与惰性匹配:

  • {}?+*默认是贪婪匹配,会匹配最多
  • 惰性匹配为{}?+*后加?,会匹配最少

例,利用惰性匹配匹配id<div id="divId" class="divClass"></div>

'<div id="divId" class="divClass"></div>'.match(/id=".*?"/)

去掉?会贪婪匹配class中最后一个"。但是上面方法性能比较低,因为存在回溯,即从i开始每次都要先检查",可以优化成/id="[^"]*"/

位置匹配(同一位置可以匹配多次)

  1. ^匹配第一个字符前的位置
  2. $匹配最后一个字符后的位置
  3. \b匹配\w的前后位置 \B匹配非\b的其它位置
  4. ?=表达式 匹配表达式前的位置。?!表达式 表示无法匹配表达式前的位置,即没有该表达式 例,匹配密码,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())
  1. ?<=表达式,匹配表达式后面的位置,记忆:<=看成是箭头,?看成是位置,及?左边是表达式。?<!表达式,与?<=相反

括号

  1. |配合表示分支
  2. 分组引用 'abab cd'.match(/(ab)+/) 得到的结果是['abab', 'ab'],第二个参数开始,如果有括号,则对匹配到的结果,按括号顺序,将最后一个括号内匹配到的接口列出来。例如'12345'.match(/(\d)+/)['12345', '5']。同时可以对括号匹配到的值赋值给$n,n->1-99
  3. 反向引用:用\n (n->1-99)匹配之前括号匹配到的值,例如/\d{4}(-|\/|\.)\d{2}\1\d{2}/即可匹配2021-12-12,而无法匹配2021/12-12
  4. 取消捕获:如果括号内只是由于逻辑原因加的括号,并且不想被捕获,使用(?:表达式)即可

回溯

当前子匹配规则匹配中无法选中,需回溯到上一匹配,然后再使用下一规则

例:/ab{1,3}bbc/.test('abbbc'),匹配结果为true,但匹配过程是ab{1,3}匹配abbb,然后匹配c的时候发现匹配失败,则会回溯。由此可见,回溯会影响匹配效率。

存在回溯情况

  • 贪婪匹配 不足时越前匹配越多
  • 惰性匹配 超出时越前匹配越多
  • 分支匹配

编写正则表达式注意事项

  • 先确定是否需要正则,因为可能js判断会更简便。是否需要一个复杂的正则,可以简化成多步来判断
  • 先保证准确性再优化性能
  • 减少回溯

习题

  1. 逗号分隔数字,例123123123 -> 123,123,123
// 从$结尾开始算,每三个数字加一个逗号,再排出开始位置
number.replace(/(?=\B\d{3}+$)/g, ',')
  1. 转小驼峰,例ab_cd_ef -> abCdEfab-cd-ef -> abCdEf
str.replace(/[_-]\w/g, e => e.toUpperCase())
  1. 转全小写,以-间隔,例abCdEf -> ab-cd-ef
str.replace(/\B([A-Z])/g, '-$1').toLowerCase()
  1. 判断颜,例#fff、#ffffff
/^#([0-9a-zA-Z]{3}|[0-9a-zA-Z]{6})$/.test(str)
  1. 提取html字符串中所有图片
var list = []
document.body.innerHTML.replace(/<img[^>]*?src="([^"]*)"/g, (_, s) => list.push(s))