应区分输入来源:硬编码字面量用MustCompile,用户输入或配置等动态场景必须用Compile并检查error;MustCompile编译失败直接panic且不返回原始错误信息,Compile返回Regexp和可记录的syntax.Error便于排查。

regexp 包在 Go 中不是“写完就能跑”的玩具工具——它编译开销大、子匹配索引易错、多行匹配默认失效、替换不自动解析 $1。线上出问题,往往不是正则写错了,而是用错了 API 或忽略了上下文约束。
regexp.Compile 和 regexp.MustCompile 怎么选
必须区分输入来源:硬编码字面量可用 MustCompile;其余一律走 Compile。
- 用户输入、配置文件读取、环境变量拼接的 pattern,
MustCompile会 panic,且错误信息不带原始字符串,无法定位哪段语法错 -
Compile返回(*Regexp, error),可记录完整 pattern + err,方便排查 - 包级变量推荐用
var re = regexp.MustCompile(...),但别放在函数体内——Go 不保证初始化顺序,可能触发竞态或延迟 panic
提取多个捕获组为什么总是取不到值
FindStringSubmatch 和 FindSubmatch 返回结构不同,且 nil 安全性差,是高频踩坑点。
-
FindStringSubmatch("id=(\d+)&name=(\w+)")返回的是[]string,但只含完整匹配,不拆组 - 真正要取捕获组,得用
FindSubmatch([]byte(src)):返回[][]byte,result[0]是完整匹配,result[1]是第一个(),result[2]是第二个 - 如果没匹配上,这些函数返回
nil,直接下标访问会 panic;务必先判空:if len(submatches) > 2 { ... } - 命名捕获组(
(?P<year>\d{4})</year>)在|拼接的复合正则中会导致SubexpNames()返回错位名称,应拆成多个独立正则分别匹配
为什么 ReplaceAllString 替换后出现字面量 $1
Go 的 ReplaceAllString 默认不解析 $n 占位符——这不是 bug,是设计行为。
- 想用
$1,必须改用ReplaceAllStringSubmatch,传入[]byte和替换模板字符串 - 或者用
ReplaceAllFunc手动提取再拼接,更可控:re.ReplaceAllFunc(s, func(m string) string { sub := re.FindSubmatch([]byte(m)); return string(sub[1]) + "-" + string(sub[2]) }) - 注意:所有
Replace*系列函数对未匹配文本原样保留,不会报错或跳过
多行文本匹配总失败,. 为什么不匹配换行符
默认情况下,. 不匹配 \n、\r —— 这是 RE2 引擎的明确约定,不是 Go 特有。
立即学习“go语言免费学习笔记(深入)”;
- 启用单行模式:在 pattern 开头加
(?s),例如(?s)start.*end - 兼容旧版 Go 或需显式控制:用
[\s\S]替代.,它明确覆盖所有空白与非空白字符 -
(?m)是多行模式,只影响^和$的行为(让它们匹配每行首尾),和.无关 - 日志解析等场景,优先考虑用
bufio.Scanner分行后再小段匹配,避免把整块日志喂给正则


















