正则表达式是一种进行模式匹配和文本操纵的复杂而又强大的工具。虽然正则表达式比纯粹的文本匹配效率低,但是它却更灵活,按照它的语法规则,根据需求构造出的正则表达式能够从原始文本中筛选出几乎任何你想要得到的字符组合。
Go语言通过 regexp 包为正则表达式提供了官方支持,其采用 RE2 语法,除了\c、\C外,Go语言和 Perl、Python 等语言的正则基本一致。
正则表达式语法规则
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")构成的文字序列,可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
下面的表格中列举了构成正则表达式的一些语法规则及其含义。
1) 字符
2) 数量词(用在字符或 (…) 之后)
3) 边界匹配
4) 逻辑、分组
5) 特殊构造(不作为分组)
Regexp 包的使用
下面通过几个示例来演示一下 regexp 包的使用。
【示例 1】匹配指定类型的字符串。
package main
import (
"fmt"
"regexp"
)
func main() {
buf := "abc azc a7c aac 888 a9c tac"
//解析正则表达式,如果成功返回解释器
reg1 := regexp.MustCompile(`a.c`)
if reg1 == nil {
fmt.Println("regexp err")
return
}
//根据规则提取关键信息
result1 := reg1.FindAllStringSubmatch(buf, -1)
fmt.Println("result1 = ", result1)
}
运行结果如下:
result1 = [[abc] [azc] [a7c] [aac] [a9c]]
【示例 2】匹配 a 和 c 中间包含一个数字的字符串。
package main
import (
"fmt"
"regexp"
)
func main() {
buf := "abc azc a7c aac 888 a9c tac"
//解析正则表达式,如果成功返回解释器
reg1 := regexp.MustCompile(`a[0-9]c`)
if reg1 == nil { //解释失败,返回nil
fmt.Println("regexp err")
return
}
//根据规则提取关键信息
result1 := reg1.FindAllStringSubmatch(buf, -1)
fmt.Println("result1 = ", result1)
}
运行结果如下:
result1 = [[a7c] [a9c]]
【示例 3】使用 \d 来匹配 a 和 c 中间包含一个数字的字符串。
package main
import (
"fmt"
"regexp"
)
func main() {
buf := "abc azc a7c aac 888 a9c tac"
//解析正则表达式,如果成功返回解释器
reg1 := regexp.MustCompile(`a\dc`)
if reg1 == nil { //解释失败,返回nil
fmt.Println("regexp err")
return
}
//根据规则提取关键信息
result1 := reg1.FindAllStringSubmatch(buf, -1)
fmt.Println("result1 = ", result1)
}
运行结果如下:
result1 = [[a7c] [a9c]]
【示例 4】匹配字符串中的小数。
package main
import (
"fmt"
"regexp"
)
func main() {
buf := "43.14 567 agsdg 1.23 7. 8.9 1sdljgl 6.66 7.8 "
//解释正则表达式
reg := regexp.MustCompile(`\d+\.\d+`)
if reg == nil {
fmt.Println("MustCompile err")
return
}
//提取关键信息
//result := reg.FindAllString(buf, -1)
result := reg.FindAllStringSubmatch(buf, -1)
fmt.Println("result = ", result)
}
运行结果如下:
result = [[43.14] [1.23] [8.9] [6.66] [7.8]]
【示例 5】匹配 div 标签中的内容。
package main
import (
"fmt"
"regexp"
)
func main() {
// 原生字符串
buf := `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<title>Go语言 | Go语言入门教程</title>
</head>
<body>
<div>Go语言简介</div>
<div>Go语言基本语法
Go语言变量的声明
Go语言教程简明版
</div>
<div>Go语言容器</div>
<div>Go语言函数</div>
</body>
</html>
`
//解释正则表达式
reg := regexp.MustCompile(`<div>(?s:(.*?))</div>`)
if reg == nil {
fmt.Println("MustCompile err")
return
}
//提取关键信息
result := reg.FindAllStringSubmatch(buf, -1)
//过滤<></>
for _, text := range result {
fmt.Println("text[1] = ", text[1])
}
}
运行结果如下:
text[1] = Go语言简介
text[1] = Go语言基本语法
Go语言变量的声明
Go语言教程简明版
text[1] = Go语言容器
text[1] = Go语言函数
【示例 6】通过 Compile 方法返回一个 Regexp 对象,实现匹配,查找,替换相关的功能。
package main
import (
"fmt"
"regexp"
"strconv"
)
func main() {
//目标字符串
searchIn := "John: 2578.34 William: 4567.23 Steve: 5632.18"
pat := "[0-9]+.[0-9]+" //正则
f := func(s string) string{
v, _ := strconv.ParseFloat(s, 32)
return strconv.FormatFloat(v * 2, 'f', 2, 32)
}
if ok, _ := regexp.Match(pat, []byte(searchIn)); ok {
fmt.Println("Match Found!")
}
re, _ := regexp.Compile(pat)
//将匹配到的部分替换为 "##.#"
str := re.ReplaceAllString(searchIn, "##.#")
fmt.Println(str)
//参数为函数时
str2 := re.ReplaceAllStringFunc(searchIn, f)
fmt.Println(str2)
}
输出结果:
Match Found!
John: ##.# William: ##.# Steve: ##.#
John: 5156.68 William: 9134.46 Steve: 11264.36
上面代码中 Compile 方法可以解析并返回一个正则表达式,如果成功返回,则说明该正则表达式正确可用于匹配文本。
另外我们也可以使用 MustCompile 方法,它也可以像 Compile 方法一样检验正则的有效性,但是当正则不合法时程序将 panic。