推荐使用正则-?\b(0[xx][0-9a-fa-f]+|[0-9]+(\.[0-9]+)?([ee][+-]?[0-9]+)?|0[bb][01]+|0[oo][0-7]+)\b提取go源码中十进制/浮点/十六进制/二进制/八进制数字字面量,但无法处理复数、注释和字符串内的数字,准确提取应使用go/parser+go/ast。

如何用 regexp 提取 Go 源文件中的所有数字字面量
Go 源码里的数字不只有整数,还有浮点、十六进制、科学计数法、复数后缀(如 1e2、0xFF、3.1415、1+2i),直接用 \d+ 会漏掉大部分。标准做法是复用 Go 词法分析器的数字识别逻辑,但若只做轻量提取,正则仍可行——关键是选对模式。
推荐使用这个正则:`-?\b(0[xX][0-9a-fA-F]+|[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?|0[bB][01]+|0[oO][0-7]+)\b`,它覆盖:
• 十进制整数/浮点(含小数点和指数)
• 十六进制(0x)、二进制(0b)、八进制(0o)
• 支持负号(-123、-0x1F)
• \b 防止匹配到变量名里(比如 version2 中的 2 不会被单独捕获)
- 别忘了用
regexp.MustCompile编译一次复用,避免每次调用都编译 - 匹配时用
FindAllString而非FindAllStringSubmatch,除非你需要区分不同捕获组 - 注意:该正则不匹配复数字面量(如
1i或3.14i),Go 规范中复数是float后加i,需额外加分支(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?i
为什么不能跳过 go/parser 直接靠正则“扫源码”
正则在字符串层面工作,而 Go 源码中数字可能出现在注释、字符串字面量、甚至反引号字符串里。例如:// 这里有 123 或 s := "price: .99" —— 这些 45.99 不是代码中的数值,只是文本内容。
- 真实项目中,若需准确提取“可执行代码中的数字字面量”,必须走 AST 解析:用
go/parser.ParseFile得到*ast.File,再遍历节点,对*ast.BasicLit类型且Kind == token.INT || token.FLOAT || token.IMAG的节点取Value - 正则快但粗糙;AST 慢但语义准确。二者适用场景不同:日志/配置文件快速扫描用正则,代码分析工具(如 linter、metrics 统计)必须用
go/parser+go/ast - 注意
go/parser默认不解析注释,如需排除注释内的数字,得手动跳过ast.CommentGroup节点
strconv 转换提取出的数字字符串时常见 panic 场景
即使正则匹配成功,strconv.Atoi 或 strconv.ParseFloat 仍可能 panic 或返回错误,因为 Go 源码允许下划线分隔符(如 1_000_000、0xFF_AA),而 strconv 默认不支持。
- 先用
strings.ReplaceAll(s, "_", "")清洗下划线,再传给strconv系列函数 -
0b1010_1100这类二进制字面量,strconv.ParseInt(s, 0, 64)中的base=0可自动识别前缀,但前提是已去掉下划线 - 复数字面量(如
1.23i)无法被strconv直接解析,需手动切分实部/虚部,或用第三方包如gonum/floats的辅助函数 - 超大整数(如
0x1FFFFFFFFFFFFFFF)可能溢出int64,建议统一用math/big.Int.SetString处理不确定范围的整数字面量
实际脚本中容易忽略的边界:Go 源码编码与 BOM
如果文件带 UTF-8 BOM(0xEF 0xBB 0xBF),os.ReadFile 返回的字节流开头会有这三个字节,可能导致正则从第四个字节开始匹配,漏掉文件首行的数字;更隐蔽的是,某些编辑器保存的 Go 文件用 Windows 换行(\r\n),虽不影响正则匹配,但若你后续按行统计位置,\r 会干扰索引计算。
- 读文件后,先用
bytes.TrimPrefix(data, []byte("\xef\xbb\xbf"))去 BOM - 正则匹配前,把
\r\n统一转成\n(strings.ReplaceAll(string(data), "\r\n", "\n")),避免跨平台行为差异 - 如果要保留原始位置信息(比如报错定位),别直接转 string 再正则,改用
regexp.FindAllIndex对[]byte操作,结果索引对应原始字节偏移
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











