[Go 入门] 第二十一章 正则表达式简介

Go 入门系列参考于互联网资料与 人民邮电出版社 《Go 语言入门经典》 与 《Effective Go》,编写目的在于学习交流,如有侵权,请联系删除

本文内容:

定义正则表达式

正则表达式描述了可用于数据交互的探索模式。使用正则表达式可以完成数据验证、查找数据以及操作大量文本等任务。相比于其他方法,表达式查找和模式匹配的效率要高得多。

正则表达式的用途之一是在字符串查找与指定正则表达式匹配的子串

Go 语言中,正则表达式功能是由 regex 包提供的,这个包实现了正则表达式的查找和模式匹配功能。它使用的是 RE2 语法,这大致与 Perl 和 Python 使用的语法相同。它操作的目标可以是字符串,也可以是字节

函数MatchString,接收一个正则表达式模式和一个字符串,并根据是否匹配返回 truefalse

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
"fmt"
"log"
"regexp"
)

func main() {
needle := "chocolate"
haystack := "Chocolate is my favorite !"
match, err := regexp.MatchString(needle, haystack)
if err != nil{
log.Fatal(err)
}
fmt.Println(match)
}

由于正则表达式区分大小写,因此没有找到 chocolate ,则返回 false

要以不区分大小写的模式查找,必须修改正则表达式,是其在查找单词时不区分大小写。为指定查找时不区分大小写,需要一种特殊语法

needle := "(?i)chocolate"

这样则会返回 true

熟悉正则表达式语法

正则表达式语法可参考 菜鸟教程,这里列出一些常用的字符

字符 含义
. 与换行符之前的其他任何字符都匹配
* 与零个或多个指定的字符匹配
^ 表示行首
$ 表示行尾
+ 匹配一次或多次
? 匹配零或一次
[ ] 与方括号内指定的任何字符都匹配
{n} 匹配 n 次
{n,} 匹配 n 次或更多次
{m,n} 最少匹配 m 次,最多匹配 n 次

例如需要完成以下的条件:

  • 应长于 4 个字符,但不超过 12 个
  • 应只包含字母和数字
  • 字符可大写,也可以小写

符合条件的正则表达式为:

^[a-zA-Z0-9]{5,12}$

  • 字符 ^ 表示从字符串开头开始匹配
  • 方括号 ([]) 内的字符集表示与其中的任何字符都匹配
  • 大括号 ({}) 内的数字表示应至少匹配 5 次,但最多不超过 12 次

使用正则表达式验证数据

用于分析正则表达式的函数有两个:

  • Compile : 在正则表达式未能通过编译时返回错误
  • MustCompile : 在正则表达式无法编译时引发 Panic

使用哪一个取决于具体情况,但通常使用 MustCompile 是更佳的选择

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"fmt"
"regexp"
)

func main() {
re := regexp.MustCompile("^[a-zA-Z0-9]{5,12}$")
fmt.Println(re.MatchString("fsdhuai"))
fmt.Println(re.MatchString("!shuidhuisahidu!"))
fmt.Println(re.MatchString("roger"))
fmt.Println(re.MatchString("hjsuiahdyiusaghfyudgsaiokfgdsagfydoasfd"))
}

输出的结果为:

1
2
3
4
true
false
true
false

使用正则表达式变换数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import (
"fmt"
"regexp"
)

func main() {
names := [4]string{
"fsdhuai",
"!@shuidhuisahidu",
"roger",
"hjsuiahdyiusaghfyudgsaiokfgdsagfydoasfd",
}
re := regexp.MustCompile("^[a-zA-Z0-9]{5,12}$")
an := regexp.MustCompile("[[:^alnum:]]")

for _, username := range names {
if len(username) > 12 {
username = username[:12]
fmt.Printf("trimmed username to %s\n", username)
}

if !re.MatchString(username) {
username = an.ReplaceAllString(username, "x")
fmt.Printf("Rewrote username to %s\n", username)
}
}
}

使用函数 ReplaceAllString 进行替换,使得非法字符都被替换为 “x” , 则执行后的结果为:

1
2
3
trimmed username to !@shuidhuisa
Rewrote username to xxshuidhuisa
trimmed username to hjsuiahdyius

问题列表

  • 使用 strings 包相比,使用正则表达式的效率更高还是更低

    strings包包含的几个函数不支持复杂的模式匹配,一般而言使用正则表达式匹配会更慢