官方文档
字符串相关函数
字符串函数主要来自于标准库这两个模块:
| 函数 | 描述 |
|---|---|
| strconv.len | 获取字符串长度 |
| strconv.Atoi | 字符串转整数 |
| strconv.Itoa | 整数转字符串 |
| strings.Count | 计算子字符串在字符串中出现的次数 |
| strings.Contains | 判断一个字符串是否包含子字符串 |
| strings.Index | 子字符串在字符串中出现的位置 |
| strings.EqualFold | 字符串是否相等, 忽略大小写 |
| strings.Replace | 替换字符串 |
| strings.Split | 切分字符串为字符串数组 |
| strings.ToUpper | 字母全部转换大写 |
| strings.ToLower | 字母全部转换小写 |
| strings.Trim | 去除字符串两边的指定字符 |
| strings.TrimSpace | 去除字符串两边的空格 |
| strings.TrimLeft | 去除字符串左边的指定字符 |
| strings.TrimRight | 去除字符串右边的指定字符 |
| strings.HasPrefix | 判断字符串是否以指定字符开头 |
| strings.HasSuffix | 判断字符串是否以指定字符结尾 |
go
package main
import (
"fmt"
"strconv"
"strings"
)
func main() {
//// 1.获取字符串长度
// 在 Go 语言中, 汉字是 utf-8 字符集编码, 占 3 个字节
// 你好Golang是: 3+3+6 所以是 12
str1 := "你好Golang"
fmt.Println("str1 长度是:", len(str1)) // 12
//// 2.字符串转整数
num, _ := strconv.Atoi("666")
fmt.Printf("num type:%T value:%v \n", num, num) // num type:int value:666
//// 3.整数转字符串
str3 := strconv.Itoa(66)
fmt.Printf("str2 type:%T value:%v \n", str3, str3) // num type:str value:66
//// 4.统计子字符串次数
str4 := "hello hello"
count := strings.Count(str4, "hello")
fmt.Println("count:", count) // 2
//// 5.判断一个字符串是否包含子字符串
str5 := "hello world"
isInclude := strings.Contains(str5, "world")
fmt.Println("isInclude:", isInclude) // true
//// 6.查询子字符串在字符串中出现的位置
str6 := "hello world"
index := strings.Index(str6, "world")
fmt.Println("index:", index) // 6
//// 7.比较字符串-忽略大小写
isMatched := strings.EqualFold("hello", "HELLO")
fmt.Println("isMatched:", isMatched) // true
//// 8.替换字符串 strings.Replace(origin, find, replace, count)
// origin : 原始字符串
// find : 要替换的子字符串
// replace: 替换后的字符串
// count : 替换次数
str8 := strings.Replace("hello hello hello", "hello", "hi", 2)
fmt.Println("str6:", str8) // hi hi hello
//// 9.切分字符串为字符串数组
strs := strings.Split("hello@world", "@")
fmt.Printf("strs type:%T value:%v \n", strs, strs) // strs type:[]string value:[hello world]
//// 10.转换大小写
fmt.Println(strings.ToUpper("hello world")) // HELLO WORLD
fmt.Println(strings.ToLower("hello WORLD")) // hello world
//// 11.去除指定字符串
fmt.Println(strings.TrimSpace(" hello world ")) // hello world
fmt.Println(strings.Trim(" hello world ", " ")) // hello world
fmt.Println(strings.Trim("~hello world~", "~")) // hello world
fmt.Println(strings.TrimLeft("~hello world~", "~")) // hello world~
fmt.Println(strings.TrimRight("~hello world~", "~")) // ~hello world
//// 12.判断字符串是否是以指定字符串开头/结尾
fmt.Println(strings.HasPrefix("http://example.com", "http")) // true
fmt.Println(strings.HasSuffix("http://example.com", "com")) // true
}正则表达式
正则表达式相关函数
Go语言的正则表达式使用RE2语法, 不支持回溯引用和后向断言, regexp包提供了丰富的正则表达式操作功能
go
package main
import (
"fmt"
"regexp"
)
func main() {
// 1. 编译正则表达式
// Compile 函数返回一个 Regexp 对象,可以复用,适合处理运行时动态生成的正则
re, err := regexp.Compile(`\d+`) // 匹配一个或多个数字
if err != nil {
fmt.Println("编译正则表达式失败:", err)
return
}
// MustCompile 在编译失败时会 panic,适合在程序启动时使用
re2 := regexp.MustCompile(`[a-z]+`) // 匹配一个或多个小写字母
// 2. 检查字符串是否匹配正则表达式
fmt.Println(re.MatchString("123")) // true
fmt.Println(re.MatchString("abc")) // false
fmt.Println(re2.MatchString("abc")) // true
fmt.Println(re2.MatchString("123")) // false
// 3. 查找匹配的字符串
text := "abc123def456"
fmt.Println("第一个匹配:", re.FindString(text)) // "123"
fmt.Println("所有匹配:", re.FindAllString(text, -1)) // ["123", "456"]
fmt.Println("限制匹配数量:", re.FindAllString(text, 1)) // ["123"]
// 4. 替换匹配的字符串
fmt.Println("替换所有匹配:", re.ReplaceAllString(text, "数字")) // "abc数字def数字"
// 使用函数进行替换,可以基于匹配内容动态生成替换文本
result := re.ReplaceAllStringFunc(text, func(match string) string {
return "[" + match + "]"
})
fmt.Println("函数替换:", result) // "abc[123]def[456]"
// 5. 拆分字符串
splitRe := regexp.MustCompile(`[\s,;]+`) // 匹配空白字符、逗号或分号
splitText := "apple, banana; orange grape"
fmt.Println("拆分结果:", splitRe.Split(splitText, -1)) // ["apple" "banana" "orange" "grape"]
// 6. 子匹配(捕获组)
emailRe := regexp.MustCompile(`(\w+)@(\w+)\.(\w+)`)
email := "user@example.com"
// FindStringSubmatch 返回匹配的完整字符串和所有子匹配
matches := emailRe.FindStringSubmatch(email)
fmt.Println("子匹配结果:", matches) // ["user@example.com" "user" "example" "com"]
// 只需检查是否匹配,不关心匹配内容
if emailRe.MatchString(email) {
fmt.Println("是有效的邮箱格式")
}
// 使用命名捕获组
namedRe := regexp.MustCompile(`(?P<username>\w+)@(?P<domain>\w+)\.(?P<tld>\w+)`)
namedMatches := namedRe.FindStringSubmatch(email)
// 获取子匹配名称
names := namedRe.SubexpNames()
fmt.Println("子匹配名称:", names) // ["", "username", "domain", "tld"]
for i, name := range names {
if i != 0 && name != "" { // 跳过完整匹配(索引0)和无名组
fmt.Printf("%s: %s\n", name, namedMatches[i])
}
}
}常用正则表达式示例
go
package main
import (
"fmt"
"regexp"
"strings"
)
func main() {
// 1. 验证手机号 (中国)
mobileRe := regexp.MustCompile(`^1[3-9]\d{9}$`)
fmt.Println("手机号验证 13800138000:", mobileRe.MatchString("13800138000")) // true
fmt.Println("手机号验证 12800138000:", mobileRe.MatchString("12800138000")) // false
// 2. 验证邮箱
emailRe := regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
fmt.Println("邮箱验证 test@example.com:", emailRe.MatchString("test@example.com")) // true
fmt.Println("邮箱验证 test@.com:", emailRe.MatchString("test@.com")) // false
// 3. 提取 URL
urlRe := regexp.MustCompile(`https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+[/\w\.-]*(?:\?[\w=&]*)?`)
textWithURLs := "访问我们的网站 https://example.com/page?param=value 获取更多信息"
urlMatches := urlRe.FindAllString(textWithURLs, -1)
fmt.Println("提取的URL:", urlMatches) // ["https://example.com/page?param=value"]
// 4. 验证日期格式 (YYYY-MM-DD)
dateRe := regexp.MustCompile(`^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$`)
fmt.Println("日期验证 2023-01-15:", dateRe.MatchString("2023-01-15")) // true
fmt.Println("日期验证 2023-13-15:", dateRe.MatchString("2023-13-15")) // false
// 5. 清理HTML标签
htmlRe := regexp.MustCompile(`</?[a-zA-Z][^>]*>`)
htmlText := "<div><p>Hello <b>World</b></p></div>"
cleanText := htmlRe.ReplaceAllString(htmlText, "")
fmt.Println("清理HTML标签后:", cleanText) // "Hello World"
// 6. IP地址验证
ipRe := regexp.MustCompile(`^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$`)
fmt.Println("IP验证 192.168.1.1:", ipRe.MatchString("192.168.1.1")) // true
fmt.Println("IP验证 256.0.0.1:", ipRe.MatchString("256.0.0.1")) // false
// 7. 与strings包结合使用 - 验证是否是小写字母开头
startsWithLower := regexp.MustCompile(`^[a-z]`)
str := "hello world"
if startsWithLower.MatchString(str) {
fmt.Printf("%q 以小写字母开头\n", str)
}
// 8. 验证十六进制颜色代码
colorRe := regexp.MustCompile(`^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$`)
fmt.Println("颜色验证 #FF5733:", colorRe.MatchString("#FF5733")) // true
fmt.Println("颜色验证 #GGGGGG:", colorRe.MatchString("#GGGGGG")) // false
}正则表达式实用技巧
- 预编译正则表达式:对于重复使用的正则表达式,应该预编译它们而不是每次重新编译
go
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)- 使用原始字符串:使用反引号(`)定义正则表达式,避免过多的转义
go
re := regexp.MustCompile(`\d+\.\d+`) // 比 "\\d+\\.\\d+" 更清晰- 性能考虑:对于简单任务,strings包的函数通常比正则表达式更高效
go
// 用strings.Contains比用正则更高效
if strings.Contains(text, "error") {
// 处理错误
}- 使用FindIndex代替FindString:当你只需要知道匹配位置而不需要匹配内容时
go
indices := re.FindIndex(text)
if indices != nil {
startPos, endPos := indices[0], indices[1]
// 使用位置信息
}- 正则表达式标志:
(?i)- 不区分大小写(?m)- 多行模式(?s)- 让.匹配包括换行符在内的所有字符
go
caseInsensitiveRe := regexp.MustCompile(`(?i)hello`) // 不区分大小写
multilineRe := regexp.MustCompile(`(?m)^start`) // 在多行模式下匹配行首注意事项
- Go的正则表达式引擎是RE2,不支持回溯引用(
\1)和后向断言 - 正则表达式在编译后可以复用,避免重复编译,提高性能
- 对于简单的字符串操作,优先考虑使用strings和strconv包,通常更高效
- 复杂的HTML/XML解析应该使用专门的解析库,而不是正则表达式
- 在处理用户输入时,注意防止正则表达式拒绝服务攻击(ReDoS)
MustCompile适合在程序初始化时使用,因为它在编译失败时会导致panic
正则表达式是强大的文本处理工具,但在Go中应谨慎使用,优先考虑更简单、更高效的strings包函数, 在使用正则表达式时,应确保它们是预编译的,以获得最佳性能,