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

查看 49|回复 1
作者:phpfpm   
-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
    在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 所以是为啥?
    二楼放测试程序,不占地儿了

    repeat, Execution, true, count

  • phpfpm
    OP
      
    ```
    package main
    import (
    "fmt"
    "regexp"
    "strings"
    "time"
    )
    func testRegexPerformance(repeatCount int) {
    testString := strings.Repeat("a", repeatCount) + "#"
    regex := regexp.MustCompile(`(\w*)*$`)
    startTime := time.Now()
    result := regex.MatchString(testString)
    endTime := time.Now()
    executionTime := endTime.Sub(startTime).Milliseconds()
    fmt.Println("Repeat Count:", repeatCount)
    fmt.Println("Execution Time:", executionTime, "milliseconds")
    fmt.Println("-----------------------------------")
    fmt.Println(result)
    }
    func main() {
    // 测试从 1 到 50 的重复次数
    for i := 1; i <= 50; i++ {
    testRegexPerformance(i)
    }
    }
    ```
    ```
    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);
    }
    ```
    <?php
    function testRegexPerformance($repeatCount) {
    $testString = str_repeat('a', $repeatCount) . '#';
    $regex = '/(\w*)*$/';
    $startTime = microtime(true);
    $result = preg_match($regex, $testString);
    $endTime = microtime(true);
    $executionTime = ($endTime - $startTime) * 1000;
    echo "Repeat Count: $repeatCount\n";
    echo "Execution Time: $executionTime milliseconds\n";
    echo "-----------------------------------\n";
    var_dump($result);
    }
    // 测试从 1 到 50 的重复次数
    for ($i = 1; $i <= 50; $i++) {
    testRegexPerformance($i);
    }
    ```
    ```
    import re
    import time
    def test_regex_performance(repeat_count):
    test_string = 'a' * repeat_count + '#'
    regex = r'(\w*)*$'
    start_time = time.time()
    result = re.match(regex, test_string)
    end_time = time.time()
    execution_time = (end_time - start_time) * 1000
    print("Repeat Count:", repeat_count)
    print("Execution Time:", execution_time, "milliseconds")
    print("-----------------------------------")
    print(result)
    # 测试从 1 到 50 的重复次数
    for i in range(1, 51):
    test_regex_performance(i)
    ```
    您需要登录后才可以回帖 登录 | 立即注册

    返回顶部