Skip to content

官方文档

字符串相关函数

字符串函数主要来自于标准库这两个模块:

函数描述
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
}

正则表达式实用技巧

  1. 预编译正则表达式:对于重复使用的正则表达式,应该预编译它们而不是每次重新编译
go
var emailRegex = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)
  1. 使用原始字符串:使用反引号(`)定义正则表达式,避免过多的转义
go
re := regexp.MustCompile(`\d+\.\d+`) // 比 "\\d+\\.\\d+" 更清晰
  1. 性能考虑:对于简单任务,strings包的函数通常比正则表达式更高效
go
// 用strings.Contains比用正则更高效
if strings.Contains(text, "error") {
    // 处理错误
}
  1. 使用FindIndex代替FindString:当你只需要知道匹配位置而不需要匹配内容时
go
indices := re.FindIndex(text)
if indices != nil {
    startPos, endPos := indices[0], indices[1]
    // 使用位置信息
}
  1. 正则表达式标志:
  • (?i) - 不区分大小写
  • (?m) - 多行模式
  • (?s) - 让.匹配包括换行符在内的所有字符
go
caseInsensitiveRe := regexp.MustCompile(`(?i)hello`) // 不区分大小写
multilineRe := regexp.MustCompile(`(?m)^start`) // 在多行模式下匹配行首

注意事项

  1. Go的正则表达式引擎是RE2,不支持回溯引用(\1)和后向断言
  2. 正则表达式在编译后可以复用,避免重复编译,提高性能
  3. 对于简单的字符串操作,优先考虑使用strings和strconv包,通常更高效
  4. 复杂的HTML/XML解析应该使用专门的解析库,而不是正则表达式
  5. 在处理用户输入时,注意防止正则表达式拒绝服务攻击(ReDoS)
  6. MustCompile适合在程序初始化时使用,因为它在编译失败时会导致panic

正则表达式是强大的文本处理工具,但在Go中应谨慎使用,优先考虑更简单、更高效的strings包函数, 在使用正则表达式时,应确保它们是预编译的,以获得最佳性能,

Released under the MIT License.