Go语言正则表达式(regexp 包)详解

Go标准库的 regexp 包基于RE2引擎实现,语法与 Perl/Python 等类似,但支持 UTF-8,全程高效且线性时间复杂度。


1. 基础使用

1
import "regexp"

编译正则(强烈推荐 pre-compile)

1
2
3
4
5
// 必须编译,避免每次匹配都解析
re := regexp.MustCompile(`\d+`) // 匹配 1 个或更多数字
// 或安全编译
re, err := regexp.Compile(`\d+`)
if err != nil { /* 处理错误 */ }

匹配

1
2
3
4
5
6
7
8
// 匹配字符串
matched := re.MatchString("123abc") // true
// 匹配字节切片
matched = re.Match([]byte("123abc"))

// 查找第一个匹配
s := re.FindString("123abc456") // "123"
b := re.Find([]byte("123abc456")) // []byte("123")

查找所有匹配

1
2
3
// 所有匹配(-1 表示全部)
all := re.FindAllString("123abc456", -1) // []string{"123", "456"}
all = re.FindAllStringIndex("123abc456", -1) // [][]int{[]int{0,3}, []int{6,9}}

子匹配(捕获组)

1
2
3
4
re2 := regexp.MustCompile(`(\d+)(\w+)`)  // 两个捕获组
result := re2.FindStringSubmatch("123abc") // []string{"123abc", "123", "abc"}
// 索引版(更快)
idx := re2.FindStringSubmatchIndex("123abc") // []int{0, 6, 0, 3, 3, 6}

替换

1
2
3
4
newStr := re.ReplaceAllString("123abc456", "NUM")  // "NUMabcNUM"
newStr = re.ReplaceAllStringFunc("123abc456", func(s string) string {
return "NUM_" + s
})

分割

1
parts := re.Split("123abc456", -1)  // []string{"", "abc", "", "def"}(包含空字符串)

2. 正则表达式语法(RE2 语法)

字符匹配

符号 含义 示例
. 任意字符(不含换行符) .
[abc] 字符类 [0-9]
[^abc] 否定字符类 [^0-9]
\d 数字(0-9) \d+
\w 单词字符 \w+
\s 空白字符 \s+

量词(重复)

符号 含义 示例
* 0 次或多次 a*
+ 1 次或多次 a+
? 0 次或 1 次 a?
{n,m} 至少 n 次至多 m 次 a{3,5}
{n,} 至少 n 次 a{3,}

分组与锚点

  • ():捕获组(子匹配)
  • (?:re):非捕获组
  • ^:字符串开头
  • $:字符串结尾
  • \A:字符串开头
  • \z:字符串结尾(不包括换行符前)

其他高级

  • (?i):大小写不敏感
  • (?m):多行模式(^ $ 匹配行首尾)
  • (?s):. 匹配换行符

注意:Go 的 regexp 不支持 lookbehind (?<=...)、(?<!...)、回溯引用 \1 等 PCRE 特性。

3. 实战示例

邮箱校验

1
2
re := regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
ok := re.MatchString("user@example.com") // true

URL 校验

1
re := regexp.MustCompile(`^(http|https)://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$`)

提取所有数字

1
2
re := regexp.MustCompile(`\d+`)
nums := re.FindAllString("价格: 123元, 数量: 456", -1) // ["123", "456"]

替换敏感信息(信用卡号)

1
2
re := regexp.MustCompile(`\d{16}`)
result := re.ReplaceAllString("卡号: 1234567890123456", "XXXX")

4. 性能与最佳实践

  • 始终 pre-compile:var re = regexp.MustCompile(...)
  • 使用非捕获组:(?:...) 减少开销
  • 限制量词:{1,100} 而非 {,}(避免指数级回溯)
  • 小字符串:用 MatchString 或 FindString;大字符串用 FindAll + 索引
  • 错误处理:Compile 返回 error(推荐)