正则表达式
引入问题
为什么需要正则表达式。随着工作的深入,你会发现随时随地都有可能需要正则表达来提高工作效率。试想你需要过滤你想要的日志内容来排查某个bug,你会怎么做?命令grep 后面可以是一个正则表达,用于过滤匹配规则的日志类容。另外go的测试命令也有正则的影子
|
|
当要有规则地替换大量文本类容,使用正则表达是个很好的选择。比如下面这个,查出以下电话号码所对应的用户信息。最直接方法就是拼接裸sql,可是需要处理每个电话号码,如13575453505变成 “13575453505”, 每个电话号码需要引号,和一个逗号。最最最笨的方法就是一个个加,浪费时间。这时候用正则可以几秒搞定 ,替换时需要使用到捕获组,可以用()表示,并且$n进行引用,例如([0-9]),的引用是$1
(^[0-9]{11}$) “$1”,
语法
-
123+abc,可以匹配1233abc,123abc,123333abc,+号表示前面的字符至少出现有一个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
func Test2(t *testing.T) { re, err := regexp.Compile("123+abc") if err!=nil{ fmt.Println(err) return } fmt.Println(re.MatchString("1233abc")) fmt.Println(re.MatchString("123abc")) fmt.Println(re.MatchString("123333abc")) fmt.Println(re.MatchString("12abc")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test2\$ test_test.go true true true false
-
123*abc,可以匹配1233abc,123abc,123333abc,12abc, *号表示前面的字符出现有0个,1个,或多个
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
func Test3(t *testing.T) { re, err := regexp.Compile("123*abc") if err!=nil{ fmt.Println(err) return } fmt.Println(re.MatchString("1233abc")) fmt.Println(re.MatchString("123abc")) fmt.Println(re.MatchString("123333abc")) fmt.Println(re.MatchString("12abc")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test3\$ test_test.go true true true true
-
123?abc,可以匹配123abc,12abc,?号代表前面的字符最多能出现一次(0次,1次)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
func Test4(t *testing.T) { re, err := regexp.Compile("123?abc") if err!=nil{ fmt.Println(err) return } fmt.Println(re.MatchString("1233abc")) fmt.Println(re.MatchString("123abc")) fmt.Println(re.MatchString("123333abc")) fmt.Println(re.MatchString("12abc")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test4\$ test_test.go false true false true
-
匹配[…]中所有的字符,例如[hw]匹配 “hello,world”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
func Test5(t *testing.T) { re, err := regexp.Compile("[hw]") if err!=nil{ fmt.Println(err) return } fmt.Println(re.MatchString("hello,world")) fmt.Println(re.MatchString("huawei")) fmt.Println(re.MatchString("uaei")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test5\$ test_test.go 15:16:56 === RUN Test5 true true false --- PASS: Test5 (0.00s) PASS ok command-line-arguments 0.007s
-
[^….]匹配除了….的字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
func Test6(t *testing.T) { re, err := regexp.Compile("[^a]") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("a")) fmt.Println(re.MatchString("bc")) fmt.Println(re.MatchString("abc")) fmt.Println(re.MatchString("hw")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test6\$ test_test.go 15:27:59 === RUN Test6 false true true true --- PASS: Test6 (0.00s) PASS ok command-line-arguments 0.006s
-
^$,^是开始匹配,$结束匹配,可用于准确匹配
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
func Test7(t *testing.T) { re, err := regexp.Compile("^[a$bc]") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("abc")) fmt.Println(re.MatchString("abcssdda")) fmt.Println(re.MatchString("afbgch")) fmt.Println(re.MatchString("va")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test7\$ test_test.go 16:10:32 === RUN Test7 true false false false --- PASS: Test7 (0.00s) PASS ok command-line-arguments 0.008s
-
[A-Z]代表一个区间,匹配所有大写字母,[a-z]匹配所有的小写字母
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
func Test8(t *testing.T) { re, err := regexp.Compile("[a-z]") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("abc")) fmt.Println(re.MatchString("abcssdda")) fmt.Println(re.MatchString("afbgch")) fmt.Println(re.MatchString("va")) fmt.Println(re.MatchString("aA")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test8\$ test_test.go 16:14:30 === RUN Test8 true true true true false --- PASS: Test8 (0.00s) PASS ok command-line-arguments 0.006s
-
匹配所有。\s 是匹配所有空白符,包括换行,\S 非空白符,包括换行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
func Test9(t *testing.T) { re, err := regexp.Compile("[\\s]") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("abc ")) fmt.Println(re.MatchString("abcssdda\n")) fmt.Println(re.MatchString("afbgch")) fmt.Println(re.MatchString("va")) fmt.Println(re.MatchString("A")) } ⋊> ~/g/s/j/g/regular_expression go test -v -run \^Test9\$ test_test.go 16:17:54 === RUN Test9 true true false false false --- PASS: Test9 (0.00s) PASS ok command-line-arguments 0.012s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
func Test9(t *testing.T) { re, err := regexp.Compile("[\\S]") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("\n")) fmt.Println(re.MatchString(" ")) fmt.Println(re.MatchString("abcssdda\n")) fmt.Println(re.MatchString("afbgch")) fmt.Println(re.MatchString("va")) fmt.Println(re.MatchString("A")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test9\$ test_test.go 16:19:34 === RUN Test9 false false true true true true --- PASS: Test9 (0.00s) PASS ok command-line-arguments 0.006s
-
\w 匹配字母、数字、下划线。等价于 [A-Za-z0-9_]
-
{n} n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
func Test10(t *testing.T) { re, err := regexp.Compile("jav(a){2}") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("java")) fmt.Println(re.MatchString("javaa")) fmt.Println(re.MatchString("javaaa")) fmt.Println(re.MatchString("jav")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test10\$ test_test.go 18:57:33 === RUN Test10 false true false false --- PASS: Test10 (0.00s) PASS ok command-line-arguments 0.006s
-
{n,m} m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
func Test11(t *testing.T) { re, err := regexp.Compile("jav(a){2,3}$") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("java")) fmt.Println(re.MatchString("javaa")) fmt.Println(re.MatchString("javaaa")) fmt.Println(re.MatchString("javaaaa")) fmt.Println(re.MatchString("jav")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test11\$ test_test.go 13:46:57 === RUN Test11 false true true false false --- PASS: Test11 (0.00s) PASS ok command-line-arguments 0.007s
-
{n,} n 是一个非负整数。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
func Test12(t *testing.T) { re, err := regexp.Compile("[a-z]{5,}") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("ja")) fmt.Println(re.MatchString("javaa")) fmt.Println(re.MatchString("javaaa")) fmt.Println(re.MatchString("javaaaa")) fmt.Println(re.MatchString("av")) fmt.Println(re.MatchString("j")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test12\$ test_test.go 13:56:54 === RUN Test12 false true true true false false --- PASS: Test12 (0.00s) PASS ok command-line-arguments 0.007s
-
| 两边的字母或子式都可匹配匹配,可以理解或
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
func Test16(t *testing.T) { re, err := regexp.Compile("^(jav)$|^(cor)$") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("jav")) fmt.Println(re.MatchString("cor")) re, err = regexp.Compile("b|corn") if err != nil { fmt.Println(err) return } fmt.Println(re.MatchString("born")) fmt.Println(re.MatchString("corn")) } ⋊> ~/g/s/j/g/regular_expression go test --count=1 -v -run \^Test16\$ test_test.go 11:02:03 === RUN Test16 true true true true --- PASS: Test16 (0.00s) PASS ok command-line-arguments 0.009s
-
\b匹配一个单词的边界
-
特殊字符,如果需要匹配下面特殊字符本身,需要转义字符转义 \
$ | 匹配输入字符的结束位置 |
---|---|
() | 标记一个子表达式的开始结束位置 |
* | 匹配前面的子表达式0个,或多个 |
+ | 匹配前面的子表达式最少一个 |
. | 匹配除换行符 \n 之外的任何单字符 |
[ | 标记一个中括号表达式的开始 |
? | 匹配前面的子表达式最多一个 |
\ | 将下个字符变成特殊字符 |
^ | 匹配输入字符的开始位置 |
{ | 标记限定符表达式的开始 |
| | 选择性匹配 |
/b | 匹配一个单词的边界 |
-
修饰符
i | ignore - 不区分大小写 |
---|---|
g | global - 全局匹配 |
m | multi line -多行匹配 |
常用正则表示
-
邮箱
-
支持英文,多级域名 只允许英文字母、数字、下划线、英文句号、以及中划线组成
1
^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
-
支持中文、字母、数字,域名只允许英文域名
1
^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$
-
-
电话号码
1
^1(?:3\d|4[4-9]|5[0-35-9]|6[67]|7[013-8]|8\d|9\d)\d{8}$
-
匹配一行字符串
1 2 3 4 5 6 7 8
(^\S{1,}$) 需求是 下面随机字符串,需要替换成 "Ericwang100", Ericwang100 FSRunner VK李康 尚文欢shangwh lowkeyd stonezou
-
匹配每一行并且加上引号
1 2 3 4 5
\b(\w+)\b "$1", aaaaa asdasdsad asdasdsa