Go 入门(11):正则表达式——regexp 包基本用法
更新时间:2026-09-01。本文是
languages/go/beginner/入门层第 11 篇,接 字符串操作。Go 的regexp包实现 RE2 语法(不是回溯 NFA),保证线性时间,不会出现"灾难性回溯"。但正则语法和 Perl 不完全兼容。
本文要回答的问题
- Go 正则和 PCRE/Perl 正则有什么不同?哪些特性没有?
- Compile 和 MustCompile 有什么区别?
- 匹配、查找、替换怎么用?
- 为什么一定要预编译正则?
一、基础用法
编译正则
go
// 编译正则,可能失败
re, err := regexp.Compile(`\d+`)
if err != nil {
log.Fatal(err)
}
// 编译失败直接 panic——适合在初始化时用,反正正则错了得马上知道
re := regexp.MustCompile(`\d+`)MustCompile 适合用在全局变量初始化,编译失败就 panic,比在运行时才发现好。
匹配
go
matched, _ := regexp.MatchString(`\d+`, "hello 123") // true
// 注意:regexp.MatchString 每次重新编译正则,性能差
// 如果复用,用 Compile 编译好再调用查找
go
re := regexp.MustCompile(`\d+`)
// 第一个匹配
s := re.FindString("abc 123 def 456") // "123"
// 所有匹配
all := re.FindAllString("abc 123 def 456", -1) // ["123" "456"]
// 第二个参数是匹配次数,-1 表示全部
// 带括号的匹配(子匹配)
re = regexp.MustCompile(`(\d+)-(\w+)`)
m := re.FindStringSubmatch("id-123-abc") // ["123-abc" "123" "abc"]
// m[0] 是整个匹配,m[1] 是第一个括号,m[2] 是第二个替换
go
re := regexp.MustCompile(`\d+`)
// 替换所有匹配
s := re.ReplaceAllString("id: 123, age: 25", "[NUM]") // "id: [NUM], age: [NUM]"
// 替换并引用匹配
s = re.ReplaceAllString("id: 123", "$0") // "$0" 表示整个匹配
// 用函数替换
s = re.ReplaceAllStringFunc("id: 123", func(m string) string {
return "(" + m + ")"
}) // "id: (123)"二、RE2 与 Perl 正则的区别
Go 的 regexp 使用 RE2 引擎,不是常见正则库用的回溯 NFA:
| 特性 | RE2(Go) | PCRE/Perl |
|---|---|---|
| 性能 | 线性时间,无灾难性回溯 | 可能指数级 |
回溯引用 \1 等 | ❌ 不支持 | ✅ 支持 |
零宽断言 (?=) (?! | ❌ 不支持 | ✅ 支持 |
递归 (?R) | ❌ 不支持 | ✅ 支持 |
原子分组 (?>...) | ❌ 不支持 | ✅ 支持 |
| 编译后匹配 | 很快 | 很快 |
为什么 Go 不支持回溯引用? 因为回溯引用需要回溯 NFA,可能导致指数级匹配时间,违背 RE2 的"线性时间保证"。Go 选择安全,而不是功能全。
三、预编译:性能关键
go
// 差:每次匹配都重新编译
for _, s := range inputs {
matched, _ := regexp.MatchString(`\d+`, s)
}
// 好:编译一次,复用
re := regexp.MustCompile(`\d+`)
for _, s := range inputs {
matched := re.MatchString(s)
}四、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 循环里编译正则 | 每次循环编译,慢 | 外面 Compile 编译好 |
| MatchString 每次编译 | 隐含的编译,性能差 | 预编译再用 |
| 期望回溯引用 | 编译不报错,但不匹配 | 手动写代码代替 |
| 正则表达式不匹配 | 硬查是不是语法错了 | 用 https://regex101.com 先测 |
相关与延伸
下一篇:时间处理——time 包;RE2 正则的详细语法参考 官方文档;Go 正则的线性时间保证,在专家层讲安全与性能。
一句话总结
Go 正则:regexp.MustCompile 预编译,MatchString 判断是否匹配,FindString 查找,FindAllString 查找全部,ReplaceAllString 替换;Go 使用 RE2 引擎,保证线性时间,但不支持回溯引用和零宽断言,安全优先于功能全。