Golang 的正则表达

首先介绍一下正则表达式基础

 元字符

 空白字符

| 字符 | 描述 |
| :-: | :-: |
| \f | 匹配一个换页符 |
| \n | 匹配一个换行符 |
| \r | 匹配一个回车符 |
| \t | 匹配一个制表符 |
| \v | 匹配一个垂直制表符 |

 表示位置的字符

| 字符 | 描述 |
| :-: | :-: |
| ^ | 匹配输入字符串开始的位置 |
| $ | 匹配输入字符串结尾的位置 |

 常用

| 字符 | 描述 |
| :-: | :-: |
| \d | 匹配一个数字字符。等价于 [0-9] |
| \D | 匹配一个非数字字符。等价于 [^0-9] |
| \w | 匹配字母、数字、下划线。等价于'[A-Za-z0-9]' |
| \W | 匹配非字母、数字、下划线。等价于 '[^A-Za-z0-9
]' |
| \s | 匹配任何空白字符,包括空格、制表符、换页符 |
| \S | 匹配任何非空白字符。等价于 [^ \f\n\r\t\v] |
| . | 匹配除换行符(\n、\r)之外的任何单个字符。要匹配包括 '\n' 在内的任何字符,请使用像"(. |
| \b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er' |
| \B | 与 \b 相反:er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er' |

 简单Demo

# 匹配以ing结尾的单词
ing\b
# 匹配11位数的中国手机号
1\d\d\d\d\d\d\d\d\d\d

 区间

| 字符 | 描述 |
| :-: | :-: |
| [0-9] | 匹配0-9之间的数字 |
| [A-Z] | 匹配A-Z之间的数组,也可以组合 [A-Za-z0-9] |

 限定符

| 字符 | 描述 |
| :-: | :-: |
 | 匹配前面的 子表达式 >=0次,例如,zo 能匹配 "z" 以及 "zoo"。 等价于{0,}|
| + | 匹配前面的 子表达式 >=1次,例如,'zo+' 能匹配 "zo" 以及 "zoo",但不能匹配 "z"。+ 等价于 {1,} |
| ? | 匹配前面的 子表达式 0/1次,例如,"do(es)?" 可以匹配 "do" 、 "does" 中的 "does" 、 "doxy" 中的 "do" 。? 等价于 {0,1} |
| {n} | n 是一个非负整数。匹配确定的 n 次。例如,'o{2}' 不能匹配 "Bob" 中的 'o',但是能匹配 "food" 中的两个 o |
| {n,} | n 是一个非负整数。至少匹配n 次。例如,'o{2,}' 不能匹配 "Bob" 中的 'o',但能匹配 "foooood" 中的所有 o。'o{1,}' 等价于 'o+'。'o{0,}' 则等价于 'o
' |
| {n,m} | m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o。'o{0,1}' 等价于 'o?'。请注意在逗号和两个数之间不能有空格 |

- 上面学习了:区间、限定符,结合元字符,有了他们三种

# 匹配九位数的qq邮箱
[0-9]{9}@qq.com
# 身份证号
\d{17}[0-9Xx]|\d{15}
# ip地址
\d{0,3}.\d{0,3}.\d{0,3}.\d{0,3}

 普通字符 & 转义

# 例子
\w[-\w.+]*@([A-Za-z0-9][-A-Za-z0-9]+\.)+[A-Za-z]{2,14}

- @ 就是普通字符,标识必定会出现的内容。 比如:匹配域名 juejin.im,你完全可以用

https://juejin.im

- 但由于符号 /、.、(、) 等等在正则是特殊字符,所以需要用转义符 \ 转义

https:\/\/juejin\.im

 接下来说一些正则表达式中的一些重要概念喽

- 子表达式

用圆括号组成一个比较复杂的匹配模式,那么一个圆括号的部分我们可以看作是一个子表达式。

- 举例 var reg=/(\d)([a-z]*)/gi
    - (\d)就是第一个子表达式
    - ([a-z]) 是第二个子表达式

Golang 中使用

package main

import (
    "fmt"
    "regexp"
)

func main() {

    // 检查电话号码是否匹配正则表达式
    // regexp.Match 和 regexp.MatchString 没什么区别,只是接受的参数类型不同
    phoneNumber := "0931-87562387"
    fmt.Println(regexp.Match(`^\d{4}-\d{8}$`, []byte(phoneNumber))) // true <nil>
    fmt.Println(regexp.MatchString(`^\d{4}-\d{8}$`, phoneNumber))   // true <nil>

    text := "Hello 世界!123 Go."

    // regexp.Compile, 创建正则表达式对象, 还有一个方法与它类似,
    // regexp.MustCompile, 但在解析失败的时候回panic,常用于全局正则表达变量的安全初始化
    reg, _ := regexp.Compile(`[a-z]+`) // 查找连续的小写字母

    // regexp.Regexp.FindAll 于 FindAllString 类似
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["ello" "o"]

    reg, _ = regexp.Compile(`[^a-z]+`)              // 查找连续的非小写字母
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["H" " 世界!123 G" "."]

    reg, _ = regexp.Compile(`\w+`)                  // 查找连续的单词字母
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello" "123" "Go"]

    reg, _ = regexp.Compile(`[[:upper:]]+`)         // 查找连续的大写字母
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["H" "G"]

    reg, _ = regexp.Compile(`[[:^ascii:]]+`)        // 查找连续的非ascii字符串
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["世界!"]

    reg, _ = regexp.Compile(`[\pP]+`)               // 查找连续的标点符号
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["!" "."]

    reg, _ = regexp.Compile(`[\PP]+`)               // 查找连续的非标点符号
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello 世界" "123 Go"]

    reg, _ = regexp.Compile(`[\p{Han}]+`)           // 查找连续的汉字
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["世界"]

    reg, _ = regexp.Compile(`Hello|Go`)             // 查找Hello或者Go
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello" "Go"]

    reg, _ = regexp.Compile(`(?:Hell|G)o`)          // 查找Hello或者Go
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello" "Go"]

    reg, _ = regexp.Compile(`^H.*\s`)               // 查找行首以 H 开头,以空格结尾的字符串
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello 世界!123 "]

    reg, _ = regexp.Compile(`(?U)^H.*\s`)           // 查找行首以 H 开头,以空格结尾的字符串 非贪婪模式
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello "]

    reg, _ = regexp.Compile(`(?i:^hello).*Go`)      //  查找以 hello 开头(忽略大小写),以 Go 结尾的字符串
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello 世界!123 Go"]

    reg, _ = regexp.Compile(`\QGo.\E`)              // 查找 Go.
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Go."]

    reg, _ = regexp.Compile(`(?U)^.* `)             // 查找从行首开始,以空格结尾的字符串(非贪婪模式)
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello "]

    reg, _ = regexp.Compile(` [^ ]*$`)              // 查找以空格开头,到行尾结束,中间不包含空格字符串
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // [" Go."]

    reg, _ = regexp.Compile(`(?U)\b.+\b`)           // 查找“单词边界”之间的字符串
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello" " 世界!" "123" " " "Go"]

    reg, _ = regexp.Compile(`[^ ]{1,4}o`)           // 查找连续 1 次到 4 次的非空格字符,并以 o 结尾的字符串
    fmt.Printf("%q\n", reg.FindAllString(text, -1)) // ["Hello" "Go"]

    reg, _ = regexp.Compile(`(Hell|G)o`)                      // 查找 Hello 或 Go,替换为 Hellooo、Gooo
    fmt.Printf("%q\n", reg.ReplaceAllString(text, "${1}ooo")) // "Hellooo 世界!123 Gooo."

    reg, _ = regexp.Compile(`(Hello)(.*)(Go)`)               // 交换Hello和Ho
    fmt.Printf("%q\n", reg.ReplaceAllString(text, "$3$2$1")) // "Go 世界!123 Hello."

    reg = regexp.MustCompile(`[\f\t\n\r\v\123\x7F\x{10FFFF}\\\^\$\.\*\+\?\{\}\(\)\[\]\|]`) // 特殊字符的查找
    fmt.Printf("%q\n", reg.ReplaceAllString("\f\t\n\r\v\123\x7F\U0010FFFF\\^$.*+?{}()[]|", "-"))

}
本作品采用《CC 协议》,转载必须注明作者和本文链接
qinhan
讨论数量: 2
qinhan

欢迎指正

4年前 评论
qinhan

欢迎指正

4年前 评论

markdown 编辑得些许潦草 :joy:

4年前 评论
qinhan (楼主) 4年前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!