JS 中正则表达式的“坑”

  |   0 评论   |   0 浏览   |   Erioifpud

“坑”在哪?

这篇文章的主角是 JS 正则表达式中的 test 方法,这个方法是用来检查正则表达式是否能匹配上给定字符串的,在我发现这个问题之前,我的使用方式是:

let re = /javascript/g
re.test('Hello, javascript')
re.test('Hi, javascript')

我期望得到的结果是两个 true,但实际的结果并不是这样的:

https://s1.ax1x.com/2020/08/26/d2ONp4.png

我的第一反应是正则表达式写错了,于是在 Regex101 上测试了一遍,但没有发现问题。

问题定位

如果正则表达式没有问题,那出问题的可能是 test 本身?查看 MDN 的相关页面后,我发现 test 的行为并不像想象中那么简单,我遇到的问题只会在使用了全局标志 g 后出现,如图:

https://s1.ax1x.com/2020/08/26/d2OU1J.png

那么全局标志 g 为什么会影响结果呢,实际上这里每次调用 test,使用的都是同一个正则对象 retestexec 都会修改 re 中的 lastIndex 字段,这个字段表示开始匹配的位置。

let re = /javascript/g
re.test('Hello, javascript')
re.test('Hi, javascript')
re.test('Hello, javascript')

那么上面这段代码的运行过程是:

  1. lastIndex 一开始是 0,表示从字符串的开头进行匹配,在 7 的位置发现了第一个“JavaScript”,这时候 lastIndex 就到了匹配结果的末尾 17。
  2. 第二次调用 test 时就会从现有的 lastIndex(17)开始,谁知道第二个字符串比较短,17 早就超过边界了,那当然匹配不到了,所以返回了 false
  3. 第三次调用时,查看 lastIndex,在上次匹配失败后被重置为了 0,所以这次是能正确匹配的。

解决方法

  1. 使用字符串的 match 方法代替,'javascript'.match(/javascript/g)
  2. 在每次调用 test 前,都手动清空一遍共用正则表达式对象 relastIndex
  3. 不要使用共用的正则表达式对象,每次 test 前都新建一个 re 对象。
  4. 考虑不使用全局标志 g

标题:JS 中正则表达式的“坑”
作者:Erioifpud
地址:https://blog.doiduoyi.com/articles/1598407240722.html

评论

发表评论