/(w*)*$/.test(‘aaa#’)这个正则导致我们的页面炸了……不同语言居然不一样

21次阅读

共计 1343 个字符,预计需要花费 4 分钟才能阅读完成。

-2 本文用到的相关工具的版本

  • Chrome=122.0.6261.69
  • Nodejs=v10.19.0
  • PHP 7.4.3-4ubuntu2.20 (cli) (built: Feb 21 2024 13:54:34) (NTS)
  • Python 3.8.10
  • go version go1.13.8 linux/amd64

(不要吐槽和讨论版本,除非你确定这玩意在新版本上没问题,生产环境随便找台机器测的)

-1 这玩意哪来的?

这玩意是我们前端同学问 GPT,如何写一个匹配网址的正则问到的。

(/^( https?://)?([da-z.-]+).([a-z.]{2,6})([/w .-]*)*/?$/).test('https://foo.com/a-long-url-contains-path-and-query-and-anchor/foo/bar/baz?boo=baa#anchor');

*** (这个真的可以执行,建议新窗口 F12 试下)***

于是,真的匹配一段文本的时候,就导致浏览器卡死了,无法做后续渲染,在 profiling 的时候查到是这个正则的问题。

0 MVP 测一下

function testRegexPerformance(repeatCount) {var testString = 'a'.repeat(repeatCount) + '#';
    var regex = /(w*)*$/;

    var startTime = process.hrtime();
    var result = regex.test(testString);
    var endTime = process.hrtime(startTime);
    var executionTime = endTime[0] * 1000 + endTime[1] / 1000000;

    console.log("Repeat Count:", repeatCount);
    console.log("Execution Time:", executionTime + "milliseconds");
    console.log("-----------------------------------" + result);
}

// 测试从 1 到 50 的重复次数
for (var i = 1; i <= 50; i++) {testRegexPerformance(i);
}
Repeat Count: 20
Execution Time: 35.191223 milliseconds
-----------------------------------true
Repeat Count: 21
Execution Time: 71.355698 milliseconds
-----------------------------------true
Repeat Count: 22
Execution Time: 140.852157 milliseconds
-----------------------------------true
Repeat Count: 23
Execution Time: 287.687666 milliseconds
-----------------------------------true
Repeat Count: 24
Execution Time: 577.368917 milliseconds
-----------------------------------true
Repeat Count: 25
Execution Time: 1148.243059 milliseconds
-----------------------------------true
Repeat Count: 26
Execution Time: 2297.804939 milliseconds

i=25 的时候,执行时间就到了秒级,之后都是指数级增长。

1 结果是 true 是符合预期的

*表示 0 个或者多个,没有任何一个 w 也是没问题的

2 Regexp.test vs String.match

# 不匹配
> 'a'.match(/(b)/)
null

# 匹配
> 'a'.match(/(b)/)
null

# 匹配
> 'aa'.match(/(a)/)
['a', 'a', index: 0, input: 'aa', groups: undefined]

# 不那么匹配
> 'aaa#'.match(/(w*)*$/)
['', undefined, index: 4, input:'aaa#', groups: undefined]

# 匹配?> /(w*)*$/.test('aaa#')
true
>

起因是我旁边的同学说.net 没有 test,只有 match,而且结果是 false

所以,js 里面如果用 match 试下,大概有三种结果:

  • 匹配:test=true
  • 不匹配:test=false
  • 不太匹配:test=true,但是 match[0]是空,1 是undefined

3 其他语言的表现?

  • js:匹配,衰减

  • PHP: 不匹配,不衰减

  • Python:None(不匹配),衰减

  • Go: 匹配,不衰减

  • F#: 匹配,衰减

4 所以是为啥?

二楼放测试程序,不占地儿了

正文完
 0