推荐使用正则-?\d+\.\d+|-?\d+提取连续数字(含负数和小数),但需配合strconv.ParseFloat校验,因正则无法准确识别123.或.45等非法格式,且不覆盖科学计数法、十六进制等Go数字字面量。

用 regexp 提取所有连续数字(含负数和小数)
Go 的 regexp 包不支持直接匹配“数字”这种语义,必须手动定义模式。常见误区是只写 \d+,它只能匹配非负整数,漏掉负号、小数点、科学计数法等。
实际要覆盖多数场景,推荐用这个模式:-?\d+\.?\d*(简单整数/小数),但注意它会把 123. 或 .45 也当有效匹配——这不是标准数字格式。更稳妥的做法是分情况:
- 整数(含负):
-?\d+ - 带小数点的浮点数(至少一位数字在小数点前后):
-?\d+\.\d+|-\.\d+|\d+\.不推荐;实际建议用-?\d+\.\d+|-?\d+,再对结果做strconv.ParseFloat校验 - 若字符串来自用户输入且需严格解析,别依赖正则一步到位,先提取候选子串,再用
strconv尝试转换
示例:
re := regexp.MustCompile(`-?\d+`)
nums := re.FindAllString("abc-42def3.14xyz+77", -1) // 得到 []string{"-42", "3", "14", "77"} —— 注意 "3.14" 被拆开了用 strings.FieldsFunc + strconv 遍历过滤(适合简单分隔场景)
如果数字被空格、逗号、分号等明确分隔(如 "12, -34, 5.6"),正则反而重,用 strings.FieldsFunc 切分后逐个尝试解析更直观、可控。
立即学习“go语言免费学习笔记(深入)”;
关键点在于:不能只靠 strings.Contains 或 unicode.IsDigit 判断——它们无法识别负号或小数点。必须交给 strconv 做最终裁定:
-
strconv.Atoi只接受整数格式,遇到"3.14"直接报错 -
strconv.ParseFloat(s, 64)能处理整数、小数、负数,但也会接受"1e2"(科学计数法),需按需约束 - 空字符串、纯符号(如
"-")、多余小数点(如"1..2")都会失败,返回 error,应忽略
示例:
parts := strings.FieldsFunc("a12b -34 c5.6 d", func(r rune) bool { return !unicode.IsDigit(r) && r != '-' && r != '.' })
var numbers []float64
for _, s := range parts {
if s == "" { continue }
if f, err := strconv.ParseFloat(s, 64); err == nil {
numbers = append(numbers, f)
}
}
regexp 提取时容易忽略的边界问题
正则提取最常踩的坑不是写错模式,而是没处理「重叠」和「嵌套」场景。例如字符串 "x123y456z" 用 \d+ 没问题,但 "price: $123.45" 中的 $ 不是数字,\d+ 仍能正确跳过;真正麻烦的是:
- 前导零:
"007"是合法整数,但strconv.Atoi解析后是7,原始格式丢失 —— 若需保留,得用字符串存 - 十六进制或八进制字面量(如
"0xFF")不会被\d+匹配,需额外模式0[xX][0-9a-fA-F]+ - Unicode 数字(如阿拉伯数字字符
١٢٣)不被\d匹配,Go 正则默认只认 ASCII 数字,需用\p{Nd}(但性能略低) - 贪婪匹配导致过长:
"123abc456"用\d+.*\d+会匹配整个串,而不是两个数字 —— 应始终用FindAllString或FindAllStringSubmatch,避免 .* 类通配
性能与可维护性怎么选:正则 vs 手动扫描
短字符串(
-
regexp编译一次复用(regexp.MustCompile),但每次FindAllString都有状态初始化开销;对于简单数字提取,纯遍历往往更快 - 手动扫描(for + rune 判断)逻辑透明,易加调试日志、跳过注释、识别单位(如
"100ms"中的100),但代码行数多 - 第三方库如
github.com/antonmedv/expr或go-pkg/zglob不解决数字提取问题,别引入无关依赖
真实项目里,80% 的需求用 regexp.MustCompile(<code>-?\d+).FindAllString 起手,再根据错误样本迭代补丁——比如发现漏了小数,就加一个 FindAllString 调用专门抓 -?\d+\.\d+,最后合并去重。别一上来就想写通用数字提取器。


















