go 正则表达式
1. 介绍
在很多情况下,我们需要对字符串进行匹配、替换、提取等操作。而正则表达式就是一种非常强大和灵活的工具,它可以用来描述字符串的特定模式。在 Go 语言中,我们可以使用内置的 regexp
包来进行正则表达式的操作。
2. 正则表达式基础
2.1 字符组
字符组是正则表达式中非常常见的一种元字符,用方括号 []
表示。字符组可以匹配其中的任意一个字符,例如 [abc]
可以匹配字符 a
、b
、c
。
示例代码如下:
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
来匹配以 a
或 b
结尾的字符串。
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 匹配字符串
使用正则表达式的最常见操作之一就是匹配字符串。我们可以使用 MatchString
或 FindString
方法来进行匹配。
示例代码如下:
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 提取子字符串
正则表达式还可以用于提取子字符串。我们可以使用 FindStringSubmatch
或 FindAllStringSubmatch
方法来提取匹配到的子字符串。
示例代码如下:
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.MustCompile
或 Regexp.Compile
方法进行编译。如果我们需要多次使用同一正则表达式,这样的操作会造成性能浪费。为了提高性能,我们可以使用 regexp.MustCompile
或 regexp.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
包提供了功能丰富的正则表达式操作。我们可以使用正则表达式来匹配、替换、提取等操作。在实际应用中,合理运用正则表达式能够大大提高字符串处理的效率和灵活性。