go 正则表达式

go 正则表达式

go 正则表达式

1. 介绍

在很多情况下,我们需要对字符串进行匹配、替换、提取等操作。而正则表达式就是一种非常强大和灵活的工具,它可以用来描述字符串的特定模式。在 Go 语言中,我们可以使用内置的 regexp 包来进行正则表达式的操作。

2. 正则表达式基础

2.1 字符组

字符组是正则表达式中非常常见的一种元字符,用方括号 [] 表示。字符组可以匹配其中的任意一个字符,例如 [abc] 可以匹配字符 abc

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("[abc]")
    fmt.Println(re.MatchString("a"))  // true
    fmt.Println(re.MatchString("b"))  // true
    fmt.Println(re.MatchString("c"))  // true
    fmt.Println(re.MatchString("d"))  // false
}

运行结果:

true
true
true
false

2.2 量词

量词可以用来指定某个字符或字符组出现的次数。常见的量词有 *+?{n}{n,}{n,m}

  • * 代表前一个字符或字符组出现 0 或多次;
  • + 代表前一个字符或字符组出现 1 或多次;
  • ? 代表前一个字符或字符组出现 0 或 1 次;
  • {n} 代表前一个字符或字符组出现恰好 n 次;
  • {n,} 代表前一个字符或字符组至少出现 n 次;
  • {n,m} 代表前一个字符或字符组出现 n 到 m 次。

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile("ab*")
    fmt.Println(re.MatchString("a"))   // true
    fmt.Println(re.MatchString("ab"))  // true
    fmt.Println(re.MatchString("abb")) // true
    fmt.Println(re.MatchString("abc")) // false

    re = regexp.MustCompile("ab+")
    fmt.Println(re.MatchString("a"))   // false
    fmt.Println(re.MatchString("ab"))  // true
    fmt.Println(re.MatchString("abb")) // true
    fmt.Println(re.MatchString("abc")) // false

    re = regexp.MustCompile("ab?")
    fmt.Println(re.MatchString("a"))   // true
    fmt.Println(re.MatchString("ab"))  // true
    fmt.Println(re.MatchString("abb")) // false
    fmt.Println(re.MatchString("abc")) // false

    re = regexp.MustCompile("ab{2}")
    fmt.Println(re.MatchString("a"))   // false
    fmt.Println(re.MatchString("ab"))  // false
    fmt.Println(re.MatchString("abb")) // true
    fmt.Println(re.MatchString("abc")) // false

    re = regexp.MustCompile("ab{2,}")
    fmt.Println(re.MatchString("a"))   // false
    fmt.Println(re.MatchString("ab"))  // false
    fmt.Println(re.MatchString("abb")) // true
    fmt.Println(re.MatchString("abbbbb")) // true
    fmt.Println(re.MatchString("abc")) // false

    re = regexp.MustCompile("ab{2,4}")
    fmt.Println(re.MatchString("a"))   // false
    fmt.Println(re.MatchString("ab"))  // fasle
    fmt.Println(re.MatchString("abb")) // true
    fmt.Println(re.MatchString("abbb")) // true
    fmt.Println(re.MatchString("abbbb")) // true
    fmt.Println(re.MatchString("abbbbb")) // false
    fmt.Println(re.MatchString("abc")) // false
}

运行结果:

true
true
true
false
false
true
true
false
false
true
true
false
false
false
true
true
true
true
false
false

2.3 特殊字符

正则表达式中有一些特殊字符,需要特殊处理。常见的一些特殊字符及其意义如下:

  • . 表示匹配任意一个字符,除了换行符;
  • \d 表示匹配一个数字字符,相当于 [0-9]
  • \D 表示匹配一个非数字字符,相当于 [^0-9]
  • \w 表示匹配一个字母、数字或下划线字符,相当于 [A-Za-z0-9_]
  • \W 表示匹配一个非字母、数字或下划线字符,相当于 [^A-Za-z0-9_]
  • \s 表示匹配一个空白字符,包括空格、制表符、换行符等;
  • \S 表示匹配一个非空白字符;
  • ^ 表示匹配字符串的开头;
  • $ 表示匹配字符串的结尾;
  • \ 用于转义特殊字符。

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`a.`)
    fmt.Println(re.MatchString("ab"))   // true
    fmt.Println(re.MatchString("ac"))  // true
    fmt.Println(re.MatchString("ad")) // true
    fmt.Println(re.MatchString("abc")) // true

    re = regexp.MustCompile(`\d+`)
    fmt.Println(re.MatchString("123")) // true
    fmt.Println(re.MatchString("abc")) // false

    re = regexp.MustCompile(`\w{2}`)
    fmt.Println(re.MatchString("ab"))   // true
    fmt.Println(re.MatchString("A1"))  // true
    fmt.Println(re.MatchString("_")) // true
    fmt.Println(re.MatchString("a")) // false

    re = regexp.MustCompile(`^ab`)
    fmt.Println(re.MatchString("abc")) // true
    fmt.Println(re.MatchString("cab")) // false

    re = regexp.MustCompile(`abc`)
    fmt.Println(re.MatchString("abc")) // true
    fmt.Println(re.MatchString("abcc")) // false

    re = regexp.MustCompile(`a\.`)
    fmt.Println(re.MatchString("a.")) // true
    fmt.Println(re.MatchString("ab")) // false
}

运行结果:

true
true
true
true
true
true
false
true
true
true
true
true
true
true
true
false
true
false

2.4 分组和引用

在正则表达式中,我们可以使用圆括号 () 来构建分组。分组可以将一些字符组合成一个整体,并应用量词、捕获和引用等操作。

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(ab)+`)
    fmt.Println(re.MatchString("ab"))   // true
    fmt.Println(re.MatchString("abab"))  // true
    fmt.Println(re.MatchString("ababab")) // true
    fmt.Println(re.MatchString("abc")) // false

    re = regexp.MustCompile(`(\d+)-\1`)
    fmt.Println(re.MatchString("123-123"))   // true
    fmt.Println(re.MatchString("123-456"))  // false

    re = regexp.MustCompile(`(a|b)c`)
    fmt.Println(re.MatchString("ac"))   // true
    fmt.Println(re.MatchString("bc"))  // true
    fmt.Println(re.MatchString("cc")) // false
}

运行结果:

true
true
true
false
true
false
true
true
false

在示例代码中,我们使用了 (ab)+ 来匹配多个连续的 ab 组合,使用 (\d+)-\1 来匹配形如 123-123 的重复字符串,使用 (a|b)c 来匹配以 ab 结尾的字符串。

2.5 非贪婪模式

在默认情况下,正则表达式会尽可能多地匹配字符。但是有时我们需要进行非贪婪匹配,即尽可能少地匹配字符。在正则表达式中,我们可以使用 ? 后缀来进行非贪婪匹配。

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`a.+?b`)
    fmt.Println(re.FindString("a123b456b"))       // "a123b"
    fmt.Println(re.FindString("a123b456bb"))      // "a123b"
    fmt.Println(re.FindString("a123b456bbb"))     // "a123b"
    fmt.Println(re.FindString("a123b456bbbbbbb")) // "a123b"
}

运行结果:

a123b
a123b
a123b
a123b

在示例代码中,我们使用了 a.+?b 来进行非贪婪匹配。

3. 使用正则表达式

3.1 匹配字符串

使用正则表达式的最常见操作之一就是匹配字符串。我们可以使用 MatchStringFindString 方法来进行匹配。

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\d+`)
    fmt.Println(re.MatchString("abc123")) // true

    re = regexp.MustCompile(`\d+`)
    fmt.Println(re.FindString("abc123def456")) // "123"
}

运行结果:

true
123

在示例代码中,我们使用 \d+ 来匹配一个或多个数字字符。

3.2 替换字符串

除了匹配字符串,我们还可以使用正则表达式进行字符串的替换。我们可以使用 ReplaceAllString 方法来进行替换操作。

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\d+`)
    result := re.ReplaceAllString("abc123def456", "X")
    fmt.Println(result) // "abcXdefX"
}

运行结果:

abcXdefX

在示例代码中,我们使用 \d+ 匹配数字字符,并使用 X 替换匹配到的数字字符。

3.3 提取子字符串

正则表达式还可以用于提取子字符串。我们可以使用 FindStringSubmatchFindAllStringSubmatch 方法来提取匹配到的子字符串。

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(\w+)\s+(\w+)`)
    result := re.FindStringSubmatch("John Smith")
    for i, match := range result {
        fmt.Printf("Group %d: %s\n", i, match)
    }
}

运行结果:

Group 0: John Smith
Group 1: John
Group 2: Smith

在示例代码中,我们使用 (\w+)\s+(\w+) 来匹配两个由空格分隔的字符串,并提取其中的子字符串。

3.4 替换函数

在替换字符串时,我们还可以使用函数来动态生成替换值。我们可以使用 ReplaceAllStringFunc 方法,并传入一个函数作为参数。

示例代码如下:

package main

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

func main() {
    re := regexp.MustCompile(`\w+`)
    result := re.ReplaceAllStringFunc("hello world", func(match string) string {
        return strings.ToUpper(match)
    })
    fmt.Println(result) // "HELLO WORLD"
}

运行结果:

HELLO WORLD

在示例代码中,我们使用 \w+ 匹配单词,并使用函数将匹配到的单词转换为大写。

4. 预编译正则表达式

在上述示例代码中,我们每次使用正则表达式都需要使用 Regexp.MustCompileRegexp.Compile 方法进行编译。如果我们需要多次使用同一正则表达式,这样的操作会造成性能浪费。为了提高性能,我们可以使用 regexp.MustCompileregexp.Compile 方法预编译正则表达式,生成一个 *Regexp 对象。

示例代码如下:

package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\d+`)
    fmt.Println(re.MatchString("abc123")) // true

    re = regexp.MustCompile(`\d+`)
    fmt.Println(re.FindString("abc123def456")) // "123"
}

运行结果:

true
123

在示例代码中,我们通过 regexp.MustCompile 方法预编译了正则表达式,并多次使用同一个正则表达式进行匹配。

5. 总结

Go 语言的 regexp 包提供了功能丰富的正则表达式操作。我们可以使用正则表达式来匹配、替换、提取等操作。在实际应用中,合理运用正则表达式能够大大提高字符串处理的效率和灵活性。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程