Go1.22中regexp.Compile的行为变更解析

Go1.22中regexp.Compile的行为变更解析 看起来,与 Go 1.21 相比,Go 1.22 中 regexp.Compile 的行为发生了变化。

以下代码在 Go 1.21 中会产生错误 Go Playground - The Go Programming Language,而在 Go 1.22 中不再产生错误 Go Playground - The Go Programming Language

func main() {
    _, err := regexp.Compile(`\K`)
    if err != nil {
        fmt.Println(err)
    }
}

这是预期的行为吗?


3 回复

感谢您的参考。这正是我一直在寻找的。


对捕获组 (?<name>) 语法的支持已在 1.22 版本中添加。请参阅此问题评论:regexp: Documentation doesn’t mention that (?<name>…) capturing group syntax isn’t currently supported · Issue #64108 · golang/go · GitHub

然而,出于某种原因,它似乎没有在 1.22 版本的发布说明中被提及。Go 1.22 Release Notes - The Go Programming Language

是的,这是 Go 1.22 中 regexp/syntax 包的预期行为变更。在 Go 1.22 之前,\K 会被解析为未知的转义序列而报错。从 Go 1.22 开始,\K 被识别为 Perl 兼容的正则表达式特性,表示“重置匹配起点”。

变更说明:

  • \K 是 PCRE 中的特性,用于将匹配的起始位置重置到当前位置
  • 匹配 \K 之前的内容不会包含在最终匹配结果中
  • Go 1.22 的 regexp 引擎现在支持此特性

示例代码:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    // 现在 Go 1.22 中可以正常编译
    re, err := regexp.Compile(`foo\Kbar`)
    if err != nil {
        fmt.Println("编译错误:", err)
        return
    }
    
    // 测试匹配
    text := "foobar"
    match := re.FindString(text)
    fmt.Printf("匹配结果: %q\n", match) // 输出: "bar"
    
    // 另一个示例:匹配邮箱用户名部分
    re2, _ := regexp.Compile(`\w+\K@`)
    email := "user@example.com"
    pos := re2.FindStringIndex(email)
    if pos != nil {
        fmt.Printf("@ 的位置: %d\n", pos[0]) // 输出: 4
    }
}

更多示例展示 \K 的用途:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    // 提取价格中的数字部分(忽略货币符号)
    re, _ := regexp.Compile(`\$\K\d+`)
    prices := []string{"$100", "Price: $250", "Total: $99.99"}
    
    for _, price := range prices {
        match := re.FindString(price)
        if match != "" {
            fmt.Printf("找到价格数字: %s\n", match)
        }
    }
    
    // 匹配特定模式后的内容
    re2, _ := regexp.Compile(`ID:\s*\K[A-Z0-9]+`)
    text := "User ID: ABC123DEF, Order ID: XYZ789"
    matches := re2.FindAllString(text, -1)
    fmt.Printf("所有ID: %v\n", matches) // 输出: [ABC123DEF XYZ789]
}

这个变更是 Go 正则表达式引擎向更完整的 PCRE 兼容性迈进的一部分。在 Go 1.22 中,\K 现在被正确识别为重置匹配起点的元字符,而不是无效的转义序列。

回到顶部