Golang 的正則表達

qinhan發表於2019-10-14

 元字元

 空白字元

| 字元 | 描述 |
| :-: | :-: |
| \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\\^$.*+?{}()[]|", "-"))

}

相關文章