Go-TrimLeft-and-TrimPrefix

今天忽然发现了一个bug,其实是我自己的错误啦,不过也可以甩锅给文档……

简而言之,是用法错误,看这样一个例子:

package main

import (
	"fmt"
	"strings"
)

func main() {
	str := "/some/key"
	fmt.Println(strings.TrimLeft(str, "/some"))
}
key

Program exited.

https://play.golang.org/p/Hn8-iVEUi-W

没毛病是吧?

如果你也觉着没毛病,那你也错啦!

package main

import (
	"fmt"
	"strings"
)

func main() {
	str := "/some/sugar"
	fmt.Println(strings.TrimLeft(str, "/some"))
}
ugar

Program exited.

https://play.golang.org/p/_-3V1PgLwjh

喂喂喂!怎么把我的sugar的s给吃了,这是bug吧!

嗯。的确是bug,不过,“凡事总要先从自身找原因”:

func TrimLeft

func TrimLeft(s string, cutset string) string

TrimLeft returns a slice of the string s with all leading Unicode code points contained in cutset removed.

其实我一开始也觉着没错,毕竟,trim左边的嘛,但实际上,还有一个TrimPrefix的函数:

TrimPrefix returns s without the provided leading prefix string. If s doesn’t start with prefix, s is returned unchanged.

这就很奇怪了, 为什么明明有一个可以用了, 还要再来一个?

em…

再读一下TrimLeft的说明吧, 如果读不懂, 就再读再读再读, 直到发现自己不明白cutset是什么意思.

— 分割线 —

看这个程序:

package main

import (
	"fmt"
	"strings"
)

func main() {

	nodeOnlinePrefix := "/nodesli"
	kvs := []string{
		"/nodes/online/1ebbaa95eba5",
		"/nodes/online/d39d0dd1c159",
		"/nodes/online/d66b00076d8c",
	}

	nodes := []string{}
	for _, v := range kvs {
		str := fmt.Sprintf("%s", v)
		fmt.Printf("online node got key %s\n", str)
		n := strings.TrimLeft(str, nodeOnlinePrefix)
		fmt.Printf("online node got node %s\n", n)
		nodes = append(nodes, strings.TrimSpace(n))
	}
	fmt.Printf("online nodes: %v\n", nodes)
}
online node got key /nodes/online/1ebbaa95eba5
online node got node 1ebbaa95eba5
online node got key /nodes/online/d39d0dd1c159
online node got node 39d0dd1c159
online node got key /nodes/online/d66b00076d8c
online node got node 66b00076d8c
online nodes: [1ebbaa95eba5 39d0dd1c159 66b00076d8c]

https://play.golang.org/p/frClAL9oGrZ

这样, 是不是清晰了一点?

这个所谓的cutset就是一个字符集, 而TrimLeft就是从左开始, 如果发现了不在cutset中的字符, 就从这个点返回.

比如有一个字符串 "1112345111", TrimLeft("1112345111", "1") 之后就成了 2345111, 对应的, TrimRight("1112345111", "1")就变成了"1112345"; Trim("1112345111", "1")则是从两头都砍, 返回的结果是"2345"

这是cutset中只有一个字符的情况, 如果集合中有多个字符,那么就从里面开始匹配, 什么时候找不到了, 就返回.

那么怎么才能砍掉开头的一个"1"呢, 就是用TrimPrefix("1112345111", "1"), 对应的, 除去末尾的话, 就用 TrimSuffix.

有很多人也遇到了相同的问题, 感觉就是写文档的人和读文档的人认知有差别, 尤其是对cutset的理解.

http://www.tapirgames.com/blog/golang-unofficial-faq#trim

呐, 有些事情不要想当然, 否则就是坑… (写代码容易, 修bug难!)

comments powered by Disqus