Go 语言正则表达式速查手册:30 分钟掌握核心语法与实战技巧

Go 语言正则表达式速查手册:30 分钟掌握核心语法与实战技巧

正则表达式在 Go 语言中的实现强大而灵活,但记不住所有语法怎么办?本文就是你的救星,适合收藏备查。

导入包

go 复制代码
import "regexp"
  • 包括编译、匹配、查找、替换等方法
  • regexp 包底层使用高效自动机实现

编译正则

MustCompile

go 复制代码
re := regexp.MustCompile(`\d+`)
  • 快速编译正则表达式
  • 编译失败时会 panic

Compile

go 复制代码
re, err := regexp.Compile(`\d+`)
if err != nil {
    log.Fatal(err)
}
  • 安全编译正则表达式
  • 返回 *Regexperror

匹配

MatchString

go 复制代码
matched, _ := regexp.MatchString(`\d+`, "123abc")
fmt.Println(matched) // true
  • 检查字符串是否匹配正则
  • 返回 boolerror

Match

go 复制代码
re := regexp.MustCompile(`\d+`)
matched := re.Match([]byte("123abc"))
fmt.Println(matched) // true
  • 检查字节切片是否匹配正则
  • 返回 bool

查找

FindString

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.FindString("123abc")
fmt.Println(result) // 123
  • 查找第一个匹配的子字符串
  • 返回 string

FindStringIndex

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.FindStringIndex("123abc")
fmt.Println(result) // [0 3]
  • 查找第一个匹配的子字符串的起止索引
  • 返回 []int

FindStringSubmatch

go 复制代码
re := regexp.MustCompile(`(\d+)(\w+)`)
result := re.FindStringSubmatch("123abc")
fmt.Println(result) // [123abc 123 abc]
  • 查找第一个匹配的子字符串及其子匹配
  • 返回 []string

FindStringSubmatchIndex

go 复制代码
re := regexp.MustCompile(`(\d+)(\w+)`)
result := re.FindStringSubmatchIndex("123abc")
fmt.Println(result) // [0 6 0 3 3 6]
  • 查找第一个匹配的子字符串及其子匹配的索引
  • 返回 []int

FindAllString

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.FindAllString("123abc456", -1)
fmt.Println(result) // [123 456]
  • 查找所有匹配的子字符串
  • 第二个参数控制返回的匹配数量

FindAllStringIndex

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.FindAllStringIndex("123abc456", -1)
fmt.Println(result) // [[0 3] [6 9]]
  • 查找所有匹配的子字符串的起止索引
  • 第二个参数控制返回的匹配数量

FindAllStringSubmatch

go 复制代码
re := regexp.MustCompile(`(\d+)(\w+)`)
result := re.FindAllStringSubmatch("123abc456def", -1)
fmt.Println(result) // [[123abc 123 abc] [456def 456 def]]
  • 查找所有匹配的子字符串及其子匹配
  • 第二个参数控制返回的匹配数量

FindAllStringSubmatchIndex

go 复制代码
re := regexp.MustCompile(`(\d+)(\w+)`)
result := re.FindAllStringSubmatchIndex("123abc456def", -1)
fmt.Println(result) // [[0 6 0 3 3 6] [6 12 6 9 9 12]]
  • 查找所有匹配的子字符串及其子匹配的索引
  • 第二个参数控制返回的匹配数量

替换

ReplaceAllString

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.ReplaceAllString("123abc456", "NUM")
fmt.Println(result) // NUMabcNUM
  • 替换所有匹配的子字符串
  • 返回新的字符串

ReplaceAllStringFunc

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.ReplaceAllStringFunc("123abc456", func(s string) string {
    return strconv.Itoa(len(s))
})
fmt.Println(result) // 3abc3
  • 使用函数替换所有匹配的子字符串
  • 函数接收匹配的子字符串,返回替换后的字符串

ReplaceAllLiteralString

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.ReplaceAllLiteralString("123abc456", "NUM")
fmt.Println(result) // NUMabcNUM
  • 替换所有匹配的字面值子字符串
  • 字面值替换不考虑元字符

分割

Split

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.Split("123abc456def789", -1)
fmt.Println(result) // [ abc def ]
  • 按正则表达式分割字符串
  • 第二个参数控制分割次数

Fields

go 复制代码
re := regexp.MustCompile(`\d+.*`)
result := re.Fields("123abc456def789")
fmt.Println(result) // [123abc456def789]
  • 按正则表达式分割字符串,返回非空字段
  • 适用于快速提取非空部分

匹配位置

FindSubmatchIndex

go 复制代码
re := regexp.MustCompile(`(\d+)(\w+)`)
result := re.FindSubmatchIndex([]byte("123abc456def"))
fmt.Println(result) // [0 6 0 3 3 6]
  • 查找第一个匹配的子匹配及其索引
  • 返回 []int

Match

go 复制代码
re := regexp.MustCompile(`\d+`)
matched := re.Match([]byte("123abc"))
fmt.Println(matched) // true
  • 检查字节切片是否匹配正则
  • 返回 bool

匹配与替换高级用法

ReplaceAll

go 复制代码
re := regexp.MustCompile(`\d+`)
result := re.ReplaceAll([]byte("123abc456"), []byte("NUM"))
fmt.Println(string(result)) // NUMabcNUM
  • 替换所有匹配的字节切片
  • 返回新的字节切片

Expand

go 复制代码
re := regexp.MustCompile(`(\d+)(\w+)`)
result := re.Expand([]byte("Pre: Sub1: Post: Sub2"), []byte("123abc"), re.FindSubmatch([]byte("123abc")))
fmt.Println(string(result)) // Pre: 123: Post: abc
  • 使用模板字符串扩展匹配结果
  • 模板字符串中的 Sub1Sub2 被子匹配替换

ExpandString

go 复制代码
re := regexp.MustCompile(`(\d+)(\w+)`)
result := re.ExpandString([]byte("Pre: Sub1: Post: Sub2"), "123abc", re.FindStringSubmatch("123abc"))
fmt.Println(string(result)) // Pre: 123: Post: abc
  • 使用模板字符串扩展匹配结果
  • 模板字符串中的 Sub1Sub2 被子匹配替换

正则表达式元字符

| 元字符 | 说明 |
|---------|----------------------|-----------------|
| . | 匹配任意字符(除换行符) |
| * | 匹配前面的字符 0 次或多次 |
| + | 匹配前面的字符 1 次或多次 |
| ? | 匹配前面的字符 0 次或 1 次 |
| ^ | 匹配字符串的开始 |
| $ | 匹配字符串的结束 |
| [] | 匹配字符集合中的任意一个字符 |
| - | 在字符集合中表示范围 |
| ` | ` | 逻辑或,匹配左边或右边的表达式 |
| () | 分组,捕获子匹配 |
| {m,n} | 匹配前面的字符至少 m 次,最多 n 次 |

常用正则表达式

邮箱校验

go 复制代码
re := regexp.MustCompile(`^[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}$`)
result := re.MatchString("example@example.com")
fmt.Println(result) // true
  • 常见邮箱格式校验

URL 校验

go 复制代码
re := regexp.MustCompile(`^(http|https)://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(/\S*)?$`)
result := re.MatchString("https://www.example.com")
fmt.Println(result) // true
  • 常见 URL 格式校验

电话号码校验

go 复制代码
re := regexp.MustCompile(`^\+?\d{10,15}$`)
result := re.MatchString("+1234567890")
fmt.Println(result) // true
  • 国际电话号码校验

日期校验

go 复制代码
re := regexp.MustCompile(`^\d{4}\-\d{2}\-\d{2}$`)
result := re.MatchString("2023-10-01")
fmt.Println(result) // true
  • 标准日期格式校验

IP 地址校验

go 复制代码
re := regexp.MustCompile(`^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`)
result := re.MatchString("192.168.1.1")
fmt.Println(result) // true
  • 标准 IPv4 地址校验

正则表达式构造

转义

go 复制代码
re := regexp.MustCompile(`\d\.\d{2}`) // 匹配 1.23
  • 使用反斜杠 \ 转义特殊字符

字符集

go 复制代码
re := regexp.MustCompile(`[a-z]`) // 匹配小写字母
  • 使用 [] 定义字符集

量词

量词 说明
* 0 次或多次
+ 1 次或多次
? 0 次或 1 次
{n} 恰好 n 次
{n,} 至少 n 次
{n,m} 至少 n 次,最多 m 次

分组与捕获

go 复制代码
re := regexp.MustCompile(`(\d+)(\w+)`)
result := re.FindStringSubmatch("123abc")
fmt.Println(result) // [123abc 123 abc]
  • 使用 () 分组,捕获子匹配

非捕获分组

go 复制代码
re := regexp.MustCompile(`(?:\d+)(\w+)`)
result := re.FindStringSubmatch("123abc")
fmt.Println(result) // [123abc abc]
  • 使用 (?:...) 创建非捕获分组

前瞻与后瞻

运算符 说明
(?=...) 正向前瞻,匹配后跟指定模式的字符串
(?!=...) 负向前瞻,匹配不后跟指定模式的字符串
(?<=...) 正向后瞻,匹配前有指定模式的字符串
(?<!...) 负向后瞻,匹配前没有指定模式的字符串

示例

go 复制代码
re := regexp.MustCompile(`\d+(?=px)`)
result := re.FindString("width: 123px")
fmt.Println(result) // 123
  • 使用正向前瞻匹配 px 前的数字

正则表达式性能优化

预编译

go 复制代码
var re = regexp.MustCompile(`\d+`)
  • 预编译正则表达式,提高性能

非捕获分组

go 复制代码
re := regexp.MustCompile(`(?:\d+)(\w+)`)
  • 减少捕获分组,提高性能

限制量词

go 复制代码
re := regexp.MustCompile(`\d{1,4}`)
  • 限制量词范围,避免过度匹配

避免使用回溯

go 复制代码
re := regexp.MustCompile(`^\d+.*\d+$`)
  • 使用非贪婪匹配或前瞻/后瞻,减少回溯

实战技巧

提取所有邮箱

go 复制代码
re := regexp.MustCompile(`[a-zA-Z0-9._%+\-]+@[a-zA-Z0-9.\-]+\.[a-zA-Z]{2,}`)
result := re.FindAllString("email@example.com, other@example.net", -1)
fmt.Println(result) // [email@example.com other@example.net]
  • 从文本中提取所有邮箱地址

替换敏感信息

go 复制代码
re := regexp.MustCompile(`\d{16}`)
result := re.ReplaceAllString("Credit card: 1234567890123456", "XXXX")
fmt.Println(result) // Credit card: XXXX
  • 替换信用卡号等敏感信息

检查用户名

go 复制代码
re := regexp.MustCompile(`^[a-zA-Z0-9]{3,16}$`)
result := re.MatchString("user123")
fmt.Println(result) // true
  • 检查用户名是否符合 3-16 位的字母数字规则

处理复杂日志

go 复制代码
re := regexp.MustCompile(`(?P<date>\d{4}\-\d{2}\-\d{2})\s(?P<time>\d{2}:\d{2}:\d{2})\s(?P<level>\w+)\s(?P<message>.*)`)
logLine := "2023-10-01 12:34:56 INFO Log message here"
result := re.FindStringSubmatch(logLine)
for i, name := range re.SubexpNames() {
    if i != 0 && name != "" {
        fmt.Printf("%s: %s\n", name, result[i])
    }
}
  • 提取日志中的日期、时间、级别和消息

推荐工具

在处理正则表达式时,Hey Cron 是一个免费在线工具网站,提供多种实用工具,包括:

  • 正则表达式生成器:中文描述秒转正则,快速生成复杂正则表达式
  • JSON 格式化:轻松格式化和验证 JSON 数据
  • Base64 编码解码:快速编码和解码 Base64 字符串
  • 时间戳转换:方便地在时间戳和日期时间之间转换
  • JWT 解析:解析 JSON Web Token,查看其内容

无论是开发还是调试,Hey Cron 都能提高你的效率。立即访问 Hey Cron 试试吧!

相关推荐
大蝴蝶博努奇a1 小时前
使用ChatGPT 解决各类代码报错
前端
胡志辉1 小时前
深入浅出 call、apply、bind
前端·javascript·后端
iccb10132 小时前
5年,一个程序员是如何把私有化在线客服系统做到第一名的
前端·后端·github
假如让我当三天老蒯2 小时前
回归基本功:Map/Set 与 WeakMap/WeakSet 的区别
前端·面试
IT乐手2 小时前
48队都装不下你|国足第24次让全世界失望
前端
SoaringHeart3 小时前
Flutter最佳实践:IM聊天文字链接自动识别跳转
前端·flutter
掘金一周4 小时前
企业中要做智能体,最佳的方案是什么? | 沸点周刊 6.18
前端·人工智能·ai编程
Darling噜啦啦4 小时前
CSS 3D 变换与 Flex 布局实战:从零打造旋转立方体
前端·css
秃头网友小李4 小时前
前端难点:keep-alive 缓存什么?RouterView 的 key 为什么要带 scopeId?
前端·vue.js