有幸认识到了正则一个很有趣的特性,叫做「反向断言」,相对而言也有一个正向断言,举个例子:

// Paul666
"Paul666".match(/Paul?6+/)

// Paul
"Paul666".match(/Paul(?=6+)/)

// 666
"Paul666".match(/(?<=Paul)6+/)

解析

他们分别的使用情形很简单:

  • 匹配字符串里面包含 Paul,且后面包含至少一个 6 的部分
  • 匹配字符串里面包含 Paul,且后面包含至少一个 6 的部分,并提取掉后面的所有 6
  • 匹配字符串里面包含 Paul,且后面包含至少一个 6 的部分,并提取掉前面的 Paul

这个例子确实比较简单,你可能觉得没啥特别的作用。我在项目里面使用到「反向断言」,主要是为了把一段 URL 里面的 ID 提取出来。

从 URL https://live.paul.ren/106789266720369/videos/224220006785235 提取出 224220006785235,使用纯 ID 形式 224220006785235 也能匹配成功

于是我首先写的正则是:

return url.match(/(?<=videos\/)[0-9]+|^[0-9]+/);

第一个条件只需要满足 videos 在 ID 的前面,然后「反向断言」就 OK,| 后面的就是纯数字匹配啦~

兼容性

这个功能确实很好用,但是等我实测上线到 Staging 环境之后才发现,这个特性无法在 Safari 下正常工作。我电脑所安装的版本是:14.1.2 (15611.3.10.1.5, 15611)

SyntaxError: Invalid regular expression: invalid group specifier name

CanIUse

既然解决不了 Safari 兼容性垃圾的问题,那就只能换个思路写了呗!于是得到了这个:

// ! Safari 不支持反向断言,只能换个思路解决
const _val = ev.target.value;

let _match = _val.match(/videos\/[0-9]+/);

if(_match ?. [0]){
  return _match[0].replace("videos/", "")
}

_match = _val.match(/^[0-9]+/);

if(_match ?. [0]){
  return _match[0];
}

就是先看看得到的 URL 符不符合要求,再通过替换为空字符串的方式(也可以用 substr 截取)得到结果。第二个匹配就是检查是否为纯数字,这个就不用详细解释了吧...