Golang中strings.Trim()方法的怪异行为解析
Golang中strings.Trim()方法的怪异行为解析 各位Gopher们,我在使用以下代码时遇到了奇怪的结果:
prefix := "/opt/research"
l := []string{
"/opt/research/comm/aa/bb/file1.xml",
"/opt/research/comm/cc/dd/file2.xml",
"/opt/research/non_comm/aa/bb/file1.xml",
"/opt/research/non_comm/cc/dd/file2.xml",
}
for _, v := range l {
fmt.Println(strings.TrimLeft(v, prefix))
}
(代码演示链接:https://play.golang.org/p/QhWN-MUk97Q)
我期望得到这样的输出:
comm/aa/bb/file1.xml
comm/cc/dd/file2.xml
non_comm/aa/bb/file1.xml
non_comm/cc/dd/file2.xml
但实际上我得到了这样的结果:
mm/aa/bb/file1.xml
mm/cc/dd/file2.xml
non_comm/aa/bb/file1.xml
non_comm/cc/dd/file2.xml
使用strings.Trim()也会出现同样的问题。
有人知道这是为什么吗?
更多关于Golang中strings.Trim()方法的怪异行为解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我认为TrimPrefix是最佳选择。
更多关于Golang中strings.Trim()方法的怪异行为解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
strings.TrimLeft的第二个参数名为cutset,而不是前缀。因此它会从左侧删除所有在cutset中的字符。
正如文档所述,同时文档也证实了以下说法:
要删除前缀,请改用TrimPrefix。
strings.TrimLeft 的行为与你的预期不符,是因为它并不是按前缀字符串来移除,而是将第二个参数视为一个字符集合(字符集),然后从字符串开头逐个移除所有出现在该字符集中的字符。
在你的例子中,prefix 是 "/opt/research",它会被当作字符集 {'/', 'o', 'p', 't', '/', 'r', 'e', 's', 'e', 'a', 'r', 'c', 'h'} 处理。
当处理第一个路径 /opt/research/comm/aa/bb/file1.xml 时,strings.TrimLeft 会从开头依次移除所有出现在字符集中的字符,直到遇到第一个不在字符集中的字符为止。
我们来看第一个路径的移除过程:
- 开头
/在字符集中 → 移除 o在字符集中 → 移除p在字符集中 → 移除t在字符集中 → 移除/在字符集中 → 移除r在字符集中 → 移除e在字符集中 → 移除s在字符集中 → 移除e在字符集中 → 移除a在字符集中 → 移除r在字符集中 → 移除c在字符集中 → 移除h在字符集中 → 移除- 接下来是
/comm/aa/bb/file1.xml吗?不对,因为h移除后,下一个字符是/(在字符集中)也会被移除,然后才是c(在字符集中)被移除,再下一个是o(在字符集中)被移除,再下一个是m(不在字符集中)停止。
所以最终剩下的是 "mm/aa/bb/file1.xml"。
正确做法:
如果你想去掉固定的前缀字符串,应该用 strings.TrimPrefix 而不是 strings.TrimLeft。
示例代码:
prefix := "/opt/research"
l := []string{
"/opt/research/comm/aa/bb/file1.xml",
"/opt/research/comm/cc/dd/file2.xml",
"/opt/research/non_comm/aa/bb/file1.xml",
"/opt/research/non_comm/cc/dd/file2.xml",
}
for _, v := range l {
fmt.Println(strings.TrimPrefix(v, prefix))
}
输出:
/comm/aa/bb/file1.xml
/comm/cc/dd/file2.xml
/non_comm/aa/bb/file1.xml
/non_comm/cc/dd/file2.xml
如果你不想要开头的 /,可以再处理一下:
for _, v := range l {
s := strings.TrimPrefix(v, prefix)
if len(s) > 0 && s[0] == '/' {
s = s[1:]
}
fmt.Println(s)
}
这样输出就是你期望的:
comm/aa/bb/file1.xml
comm/cc/dd/file2.xml
non_comm/aa/bb/file1.xml
non_comm/cc/dd/file2.xml

