正则:regexp

regexp 包为 Go 语言提供了强大的正则表达式处理能力。通过编译正则表达式并使用 Regexp 对象,你可以轻松地进行字符串匹配、查找、替换和分割等操作。基于 RE2 引擎arrow-up-right

需要注意的是:

  • 性能:编译正则表达式是一个相对昂贵的操作,建议在初始化时编译正则表达式并复用 Regexp 对象。

  • 并发安全Regexp 对象是并发安全的,可以在多个 goroutine 中共享使用。

方法命名规则​​:

∙Find(All)?(String)?(Submatch)?(Index)?:组合后缀决定返回格式。

∙All:返回所有非重叠匹配(n参数控制返回数量,-1返回全部)。

∙String:输入/输出为字符串(否则为 []byte)。

∙Submatch:包含捕获组(索引 0为完整匹配,1为第一组,依此类推)。

∙Index:返回字节索引位置(如 [start, end])。

1 常用函数

1.1 func Match(pattern string, b []byte) (matched bool, err error)

​作用​​: 检查字节切片是否包含与正则表达式匹配的子序列

参数说明

  • pattern string: 正则表达式字符串

  • b []byte: 要匹配的字节切片

返回值

  • matched bool: 如果匹配成功返回 true,否则 false

  • err error: 正则表达式解析错误或语法错误

错误情况

  • 正则表达式语法错误(如未闭合的括号、无效的转义序列等)

  • 编译正则表达式失败时返回 error

注意事项

  1. 每次调用都会编译正则表达式,频繁使用时建议使用 Compile

  2. 匹配是部分匹配(除非正则中包含 ^ 和 $)

  3. 使用 RE2 语法,不支持 Perl 扩展

  4. 适用于处理二进制数据或字节流

1.2 func MatchReader(pattern string, r io.RuneReader) (matched bool, err error)

​作用​​:从 io.RuneReader接口读取数据并检查是否匹配正则表达式。

参数说明

  • pattern:正则表达式字符串。

  • r:实现 io.RuneReader接口的数据源(如文件流、网络流)。

返回值

Match函数。

注意事项

  1. ​适用场景​​:适合流式数据或大文本,避免一次性加载内存

  2. ​性能与限制​​:同 Match,每次调用编译正则表达式。

1.3 func MatchString(pattern string, s string) (matched bool, err error)

Match

1.4 func QuoteMeta(s string) string

​作用​​:转义字符串 s中的所有正则元字符(如 .*?),使其成为字面字符串。

参数说明

  • s:待转义的字符串(如 "file.txt")。

返回值

  • 转义后的字符串(如 "file\.txt")。

注意事项

  1. ​关键用途​​:当用户输入需作为正则字面量时,必须转义以避免语法错误。

  2. ​转义范围​​:包括 \.+*?()|[]{}^$等元字符

2 类型

2.1 Regexp

Regexp类型代表一个编译后的正则表达式,它是线程安全的,可以在多个 goroutine 中并发使用。所有正则表达式操作都通过 Regexp类型的方法进行。

2.1.1 编译函数

2.1.1.1 func Compile(expr string) (*Regexp, error)

​作用​​: 编译正则表达式并返回 Regexp 对象

参数说明

  • expr string: 正则表达式字符串

返回值

  • *Regexp: 编译后的正则表达式对象

  • error: 编译错误(正则表达式语法错误)

错误情况

  • 正则表达式语法错误(如未闭合的括号、无效的转义序列等)

注意事项

  1. 如果正则表达式编译失败,返回错误

  2. 相比 MustCompile,更适合处理可能失败的正则表达式

  3. 编译后的 Regexp 对象可以重复使用,提高性能

2.1.1.2 func CompilePOSIX(expr string) (*Regexp, error)

​作用​​: 使用 POSIX ERE 语法编译正则表达式

参数说明

  • expr string: POSIX ERE 语法的正则表达式

返回值

  • *Regexp: 编译后的正则表达式对象

  • error: 编译错误

注意事项

  1. 使用 POSIX ERE (Extended Regular Expression) 语法

  2. 匹配语义与标准正则表达式略有不同(最长左匹配)

  3. 性能可能略低于标准正则表达式

2.1.1.3 func MustCompile(str string) *Regexp

​作用​​: 编译正则表达式,如果失败则 panic

参数说明

  • str string: 正则表达式字符串

返回值

  • *Regexp: 编译后的正则表达式对象

注意事项

  1. 适合在程序初始化时使用已知正确的正则表达式

  2. Compile更简洁,但不够安全

2.1.1.4 func MustCompilePOSIX(str string) *Regexp

结合了 CompilePOSIXMustCompile的特性.

2.1.2 匹配方法

2.1.2.1 func (re *Regexp) Match(b []byte) bool

​作用​​: 检查字节切片是否匹配正则表达式

2.1.2.2 参数说明

  • b []byte: 要检查的字节切片

返回值

2.1.2.3 func (re *Regexp) MatchReader(r io.RuneReader) bool

​作用​​: 从 RuneReader 读取数据并检查是否匹配

参数说明

  • r io.RuneReader: 实现 io.RuneReader 接口的数据源

返回值

  • bool: 如果匹配返回 true,否则 false

2.1.2.4 func (re *Regexp) MatchString(s string) bool

2.1.3 查找方法

2.1.3.1 func (re *Regexp) Find(b []byte) []byte

作用​​: 在字节切片中查找第一个匹配项

参数说明

  • b []byte: 要搜索的字节切片

返回值

  • []byte: 第一个匹配项的字节切片,如果没有匹配返回 nil

2.1.3.2 func (re *Regexp) FindAll(b []byte, n int) [][]byte

​作用​​: 在字节切片中查找所有匹配项

参数说明

  • b []byte: 要搜索的字节切片

  • n int: 最多返回的匹配数量,-1 表示返回所有匹配

返回值

  • [][]byte: 所有匹配项的字节切片数组

2.1.3.3 func (re *Regexp) FindString(s string) string

​作用​​: 在字符串中查找第一个匹配项

参数说明

  • s string: 要搜索的字符串

返回值

  • string: 第一个匹配项的字符串,如果没有匹配返回空字符串

2.1.4 替换方法

2.1.4.1 func (re *Regexp) ReplaceAll(src, repl []byte) []byte

​作用​​: 替换所有匹配项(字节切片版本)

参数说明

  • src []byte: 源字节切片

  • repl []byte: 替换内容

返回值

  • []byte: 替换后的字节切片

注意事项

  1. 在替换字符串中可以使用 $1, $2等引用捕获组

  2. 使用 $0引用整个匹配项

2.1.4.2 func (re *Regexp) ReplaceAllString(src, repl string) string

​作用​​: 替换所有匹配项(字符串版本)

参数说明

  • src string: 源字符串

  • repl string: 替换内容

返回值

  • string: 替换后的字符串

2.1.5 其他重要方法

2.1.5.1 func (re *Regexp) Split(s string, n int) []string

​作用​​: 使用正则表达式分割字符串

参数说明

  • s string: 要分割的字符串

  • n int: 最多分割的次数,-1 表示不限制

返回值

  • []string: 分割后的字符串数组

2.1.5.2 func (re *Regexp) SubexpNames() []string

​作用​​: 返回捕获组的名称

SubexpNames返回此正则表达式中的括号子表达式的名称。第一个子表达式的名称是names[1],因此如果m是一个匹配切片,则m[i]的名称是SubexpNames()[i]。由于整个正则表达式不能命名,names[0]始终是空字符串。该切片不应被修改。

返回值

  • []string: 捕获组名称的数组,未命名组为空字符串

2.1.5.3 func (re *Regexp) NumSubexp() int

​作用​​: 返回捕获组的数量

2.1.5.4 返回值

  • int: 捕获组的数量

3 为什么使用Regexp类型性能要好

正则表达式的编译函数(如 regexp.Compile())比直接匹配函数(如 regexp.MatchString())性能更高的主要原因在于​​避免重复编译开销​​。

直接匹配函数的内部过程

当你使用 regexp.MatchString(pattern, text)时,Go 语言在内部实际上执行以下步骤:

  1. 解析正则表达式​​:将字符串模式解析为内部数据结构

  2. 编译正则表达式​​:将解析后的结构转换为可执行的状态机

  3. 执行匹配​​:使用编译后的状态机进行文本匹配

  4. 丢弃编译结果​​:匹配完成后,丢弃编译后的状态机

每次调用 MatchString都会重复这个过程,即使使用相同的正则表达式模式。

编译函数的工作方式

当你使用 regexp.Compile(pattern)时:

  1. 解析和编译​​:只执行一次解析和编译过程

  2. 返回可重用的对象​​:返回一个 *Regexp对象,包含编译后的状态机

  3. 重复使用​​:可以多次调用该对象的匹配方法,无需重新编译

3.1 编译过程的详细分析

3.1.1 正则表达式编译的步骤

  1. ​词法分析​​:将正则表达式字符串分解为令牌(tokens)

  2. ​语法分析​​:构建抽象语法树(AST)

  3. ​状态机构建​​:将 AST 转换为非确定性有限自动机(NFA)

  4. ​状态机优化​​:可能将 NFA 转换为确定性有限自动机(DFA)

  5. ​代码生成​​:生成高效匹配的代码或数据结构

这个过程可能相当耗时,特别是对于复杂的正则表达式。

3.1.2 编译结果的复用价值

编译后的正则表达式对象包含:

  • 优化后的匹配状态机

  • 预计算的字符类映射

  • 分组和捕获结构信息

  • 其他优化数据结构

这些结构可以被无限次复用,而无需重新计算。

最后更新于