Go正则表达式

Go正则表达式教程展示了如何使用正则表达式在Go中解析文本。

$ go version
go version go1.18.1 linux/amd64

我们使用Go版本1.18。

正则表达式

正则表达式用于文本搜索和更高级的文本操作。正则表达式内置于grep和sed等工具,vi和emacs等文本编辑器,Go、Java和Python等编程语言中。

Go具有用于处理正则表达式的内置API;它位于regexp包中。

正则表达式定义了字符串的搜索模式。它用于匹配文本、替换文本或拆分文本。可以编译正则表达式以获得更好的性能。接受的正则表达式的Go语法与Perl、Python和其他语言使用的通用语法相同。

正则表达式示例

下表显示了几个正则表达式字符串。

正则表达式 含义
. 匹配任何单个字符。
? 匹配前面的元素一次或根本不匹配.
+ 匹配前面的元素一次或多次。
* 匹配前面的元素零次或多次。
^ 匹配字符串中的起始位置。
$ 匹配字符串中的结束位置.
| 交替运算符。
[abc] 匹配a或b,或c。
[a-c] 范围;匹配a或b,或c。
[^abc] 否定,匹配除a或b以外的所有内容,或c。
\s 匹配空白字符。
code>\w 匹配一个单词字符;相当于[a-zA-Z_0-9]

去正则表达式匹配字符串

MatchString函数报告字符串是否包含正则表达式模式的任何匹配项。

package main

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

func main() {

    words := [...]string{"Seven", "even", "Maven", "Amen", "eleven"}

    for _, word := range words {

        found, err := regexp.MatchString(".even", word)

        if err != nil {
            log.Fatal(err)
        }

        if found {

            fmt.Printf("%s matches\n", word)
        } else {

            fmt.Printf("%s does not match\n", word)
        }
    }
}

在代码示例中,数组中有五个单词。我们检查哪些词与.even正则表达式匹配。

words := [...]string{"Seven", "even", "Maven", "Amen", "eleven"}

我们有一个单词数组。

for _, word := range words {

我们遍历单词数组。

found, err := regexp.MatchString(".even", word)

我们使用MatchString检查当前单词是否与正则表达式匹配。我们有.even正则表达式。点(.)元字符代表文本中的任何单个字符。

if found {

    fmt.Printf("%s matches\n", word)
} else {

    fmt.Printf("%s does not match\n", word)
}

我们打印单词是否匹配正则表达式。

$ go run matchstring.go 
Seven matches
even does not match
Maven does not match
Amen does not match
eleven matches

数组中的两个单词匹配我们的正则表达式。

Go编译正则表达式

Compile函数解析正则表达式,如果成功,则返回一个Regexp对象,该对象可用于匹配文本。编译的正则表达式产生更快的代码。

MustCompile函数是一个方便的函数,它可以编译正则表达式并在无法解析表达式时发出恐慌。

package main

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

func main() {

    words := [...]string{"Seven", "even", "Maven", "Amen", "eleven"}

    re, err := regexp.Compile(".even")

    if err != nil {
        log.Fatal(err)
    }

    for _, word := range words {

        found := re.MatchString(word)

        if found {

            fmt.Printf("%s matches\n", word)
        } else {

            fmt.Printf("%s does not match\n", word)
        }
    }
}

在代码示例中,我们使用了编译后的正则表达式。

re, err := regexp.Compile(".even")

我们使用Compile编译正则表达式。

found := re.MatchString(word)

MatchString函数在返回的正则表达式对象上被调用。

package main

import (
    "fmt"
    "regexp"
)

func main() {

    words := [...]string{"Seven", "even", "Maven", "Amen", "eleven"}

    re := regexp.MustCompile(".even")

    for _, word := range words {

        found := re.MatchString(word)

        if found {

            fmt.Printf("%s matches\n", word)
        } else {

            fmt.Printf("%s does not match\n", word)
        }
    }
}

该示例使用MustCompile进行了简化。

去正则表达式FindAllString

FindAllString函数返回正则表达式的所有连续匹配项的一部分。

package main

import (
    "fmt"
    "os"
    "regexp"
)

func main() {

    var content = `Foxes are omnivorous mammals belonging to several genera 
of the family Canidae. Foxes have a flattened skull, upright triangular ears, 
a pointed, slightly upturned snout, and a long bushy tail. Foxes live on every 
continent except Antarctica. By far the most common and widespread species of 
fox is the red fox.`

    re := regexp.MustCompile("(?i)fox(es)?")

    found := re.FindAllString(content, -1)

    fmt.Printf("%q\n", found)

    if found == nil {
        fmt.Printf("no match found\n")
        os.Exit(1)
    }

    for _, word := range found {
        fmt.Printf("%s\n", word)
    }

}

在代码示例中,我们找到了单词fox的所有出现位置,包括它的复数形式。

re := regexp.MustCompile("(?i)fox(es)?")

使用(?i)语法,正则表达式不区分大小写。(es)?表示“es”字符可能包含零次或一次.

found := re.FindAllString(content, -1)

我们使用FindAllString查找所有出现的已定义正则表达式。第二个参数是要查找的最大匹配项;-1表示搜索所有可能的匹配项。

$ go run findall.go 
["Foxes" "Foxes" "Foxes" "fox" "fox"]
Foxes
Foxes
Foxes
fox
fox

我们找到了五个匹配项。

去正则表达式FindAllStringIndex

FindAllStringIndex返回匹配表达式的所有连续索引的切片。

package main

import (
    "fmt"
    "regexp"
)

func main() {

    var content = `Foxes are omnivorous mammals belonging to several genera 
of the family Canidae. Foxes have a flattened skull, upright triangular ears, 
a pointed, slightly upturned snout, and a long bushy tail. Foxes live on every 
continent except Antarctica. By far the most common and widespread species of 
fox is the red fox.`

    re := regexp.MustCompile("(?i)fox(es)?")

    idx := re.FindAllStringIndex(content, -1)

    for _, j := range idx {
        match := content[j[0]:j[1]]
        fmt.Printf("%s at %d:%d\n", match, j[0], j[1])
    }
}

在代码示例中,我们找到了文本中出现的所有fox词及其索引。

$ go run allindex.go 
Foxes at 0:5
Foxes at 81:86
Foxes at 196:201
fox at 296:299
fox at 311:314

进行正则表达式拆分

Split函数将字符串分割成由定义的正则表达式分隔的子字符串。它返回这些表达式匹配之间的一部分子字符串。

package main

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

func main() {

    var data = `22, 1, 3, 4, 5, 17, 4, 3, 21, 4, 5, 1, 48, 9, 42`

    sum := 0

    re := regexp.MustCompile(",\\s*")

    vals := re.Split(data, -1)

    for _, val := range vals {

        n, err := strconv.Atoi(val)

        sum += n

        if err != nil {
            log.Fatal(err)
        }
    }

    fmt.Println(sum)
}

在代码示例中,我们有一个逗号分隔的值列表。我们从字符串中截取值并计算它们的总和。

re := regexp.MustCompile(",\\s*")

正则表达式包括一个逗号字符和任意数量的相邻空格。

vals := re.Split(data, -1)

我们得到值的切片。

for _, val := range vals {

    n, err := strconv.Atoi(val)

    sum += n

    if err != nil {
        log.Fatal(err)
    }
}

我们遍历切片并计算总和。切片包含字符串;因此,我们使用strconv.Atoi函数将每个字符串转换为整数。

$ go run splittext.go 
189

值的总和是189。

Go正则表达式捕获组

圆括号()用于创建捕获组。这允许我们将量词应用于整个组或将交替限制为正则表达式的一部分。

要查找捕获组(Go使用术语子表达式),我们使用FindStringSubmatch函数。

package main

import (
    "fmt"
    "regexp"
)

func main() {

    websites := [...]string{"webcode.me", "zetcode.com", "freebsd.org", "netbsd.org"}

    re := regexp.MustCompile("(\\w+)\\.(\\w+)")

    for _, website := range websites {

        parts := re.FindStringSubmatch(website)

        for i, _ := range parts {
            fmt.Println(parts[i])
        }

        fmt.Println("---------------------")
    }
}

在代码示例中,我们使用组将域名分为两部分。

re := regexp.MustCompile("(\\w+)\\.(\\w+)")

我们用括号定义了两个组。

parts := re.FindStringSubmatch(website)

FindStringSubmatch返回包含匹配项的字符串片段,包括来自捕获组的字符串。

$ go run capturegroups.go 
webcode.me
webcode
me
---------------------
zetcode.com
zetcode
com
---------------------
freebsd.org
freebsd
org
---------------------
netbsd.org
netbsd
org
---------------------

Go正则表达式替换字符串

可以用ReplaceAllString替换字符串。该方法返回修改后的字符串。

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "regexp"
    "strings"
)

func main() {

    resp, err := http.Get("http://webcode.me")

    if err != nil {
        log.Fatal(err)
    }

    defer resp.Body.Close()

    body, err := ioutil.ReadAll(resp.Body)

    if err != nil {

        log.Fatal(err)
    }

    content := string(body)

    re := regexp.MustCompile("<[^>]*>")
    replaced := re.ReplaceAllString(content, "")

    fmt.Println(strings.TrimSpace(replaced))
}

该示例读取网页的HTML数据并使用正则表达式去除其HTML标记。

resp, err := http.Get("http://webcode.me")

我们使用http包中的Get函数创建一个GET请求。

body, err := ioutil.ReadAll(resp.Body)

我们读取响应对象的主体。

re := regexp.MustCompile("<[^>]*>")

这个模式定义了一个匹配HTML标签的正则表达式。

replaced := re.ReplaceAllString(content, "")

我们使用ReplaceAllString方法删除所有标签。

去正则表达式ReplaceAllStringFunc

ReplaceAllStringFunc返回一个字符串的副本,其中正则表达式的所有匹配项都已被指定函数的返回值替换。

package main

import (
    "fmt"
    "regexp"
    "strings"
)

func main() {

    content := "an old eagle"

    re := regexp.MustCompile(`[^aeiou]`)

    fmt.Println(re.ReplaceAllStringFunc(content, strings.ToUpper))
}

在代码示例中,我们将strings.ToUpper函数应用于字符串的所有循环。

$ go run replaceallfunc.go 
aN oLD eaGLe

在本教程中,我们使用了Go中的正则表达式。

列出所有Go教程。

赞(0) 打赏

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏