起因
在某次开发中,我需要做到把一串字符从一个长字符串中删除掉,我自然的想到了 strings 包中的 Trim 相关函数,毕竟 Trim* 的意思是修剪。结果程序并没有按照我的想法进行,在网上查找 Trim* 相关用法,几乎没有找到这个坑,所以这里记录一下。
结论
先说结论,如果你也想删除某个字符串中的一个子串,那么请不要使用 Trim*,而是使用 Replace / ReplaceAll。
func main() {
originString := "¡¡¡Hello, Gophers!!!"
// 删除所有的 'e'
fmt.Println(strings.ReplaceAll(originString, "e", "")) // ¡¡¡Hllo, Gophrs!!!
}
Trim 函数族
Trim / TrimLeft / TrimRight
他们都有一个共同点,就是要满足子串模式才会继续执行
先看一个例子
func main() {
originString := "¡¡¡Hello, Gophers!!!"
fmt.Println(strings.Trim(originString, "!¡")) // Hello, Gophers // 1
fmt.Println(strings.Trim(originString, "!e¡")) // Hello, Gophers // 2
fmt.Println(strings.Trim(originString, "!H¡")) // ello, Gophers // 3
fmt.Println(strings.Trim(originString, "!Hs¡")) // ello, Gopher // 4
}
Trim 内部的做法是
- 先根据第二个参数 cutset 形成一个 set
- 从左到右 + 从右到左遍历原始串,在遍历过程中遇到在 set 中的就删除,遇到没有的字符就返回
- 如果是 Trim 则会从左到右+从右到左执行,TrimLeft 和 TrimRight 则分别从左或者从右执行
// s 是原始串 as是根据 cutset 形成的 set
func trimLeftASCII(s string, as *asciiSet) string {
// 遍历,如果没有break就走到最后
for len(s) > 0 {
if !as.contains(s[0]) {
break
// 注意这里,如果原始串中的字符在 set 中没有就直接返回
// 如上面的 2 号例子,走到 'H' 发现没在 set 中,就直接返回了
}
// 每次的更新原始串操作
s = s[1:]
}
return s
}
TrimSuffix / TrimPrefix
与 Trim / TrimLeft / TrimRight 不同的是
这一族函数不会一直删,只会把前缀/后缀中包含的删除掉
如果前缀存在不同,则不会删除重叠部分,而是什么都不做
func main() {
originString := "¡¡¡Hello, Gophers!!!"
fmt.Println(strings.TrimPrefix(originString, "¡¡¡Hello, ")) // Gophers!!! // 1
fmt.Println(strings.TrimPrefix(originString, "¡¡¡")) // Hello, Gophers!!! // 2
fmt.Println(strings.TrimPrefix(originString, "¡")) // ¡¡Hello, Gophers!!! // 3
}
关键函数
func TrimPrefix(s, prefix string) string {
// HasPrefix 是一个简单的前缀比较
if HasPrefix(s, prefix) {
// 只会删除前缀
return s[len(prefix):]
}
return s
}
TrimFunc / TrimLeftFunc / TrimRightFunc
这些函数遍历原始串,根据 Func 中是否返回 true 来判断当前字符是否需要删除
例如:
func main() {
fmt.Print(strings.TrimFunc("¡¡¡Hello, Gophers!!!", func(r rune) bool {
return !unicode.IsLetter(r) && !unicode.IsNumber(r)
}))
}
func IndexFunc(s string, f func(rune) bool) int {
// 注意这里是 true
return indexFunc(s, f, true)
}
TrimSpace
这个函数是删除所有 space,包括 \n \t在内的所有空格
func main() {
fmt.Println(strings.TrimSpace(" \t\n Hello, Gophers \n\t\r\n"))
}Ï
最后
golang 的 stings 包,在业务中经常使用,如果拿不准还是要点进去仔细看一下,防止出现不符合预期的情况。