strings.Contains 是判断子串存在的最直接高效方法,语义清晰、性能好;区分大小写,需忽略时先转小写;定位全部匹配位置需手动循环调用 strings.Index 并正确更新起始偏移。

用 strings.Contains 判断子串是否存在最直接
大多数简单搜索场景,其实只是想知道某段文本里有没有某个关键词。Go 标准库的 strings.Contains 就是为此设计的,性能好、无依赖、语义清晰。
常见错误是先用 strings.Index 拿位置再判断是否为 -1,多此一举。除非你后续真要处理索引位置,否则直接用 Contains 更安全直观。
-
strings.Contains("hello world", "world")→true -
strings.Contains("Go is fast", "rust")→false - 区分大小写:
strings.Contains("API", "api")返回false,如需忽略大小写,先转小写再查(strings.ToLower)
需要定位多个匹配位置?用 strings.Index 循环调用
strings.Index 返回首次出现的索引,但标准库不提供“全部匹配位置”的内置函数。想拿到所有下标,得手动循环推进查找起点。
容易踩的坑是没更新查找起始位置,导致死循环或漏匹配;或者忘了检查返回值是否为 -1 就继续切片。
立即学习“go语言免费学习笔记(深入)”;
- 每次查完用
index + len(substr)作为下次strings.Index的起始偏移 - 切片时注意边界:
s[index+len(substr):]可能 panic,应先判断index != -1且index+len(substr) - 示例逻辑:
for i := 0; i <= len(s)-len(substr); {
index := strings.Index(s[i:], substr)
if index == -1 { break }
positions = append(positions, i+index)
i += index + len(substr)
}
模糊搜索或正则匹配?上 regexp 包但别滥用
如果搜索需求超出字面匹配——比如“以数字结尾”“邮箱格式”“含 a/b/c 其中任意一个字母”,就得用 regexp。但它比 strings 函数慢一个数量级,编译正则本身也有开销。
生产环境高频调用时,务必预编译正则对象(regexp.MustCompile),不要在循环里反复 Compile。
-
re := regexp.MustCompile(`\bgo\b`)比regexp.Compile(`\bgo\b`)更适合长期复用 - 全匹配用
re.MatchString(s),找位置用re.FindStringIndex(s),提取内容用re.FindAllString(s, -1) - 注意转义:搜索
"a.b"要写成`a\.b`,否则点号被当通配符
中文或 Unicode 字符搜索要注意 rune 级别操作
Go 字符串底层是字节序列,len("你好") 是 6 而不是 2。如果搜索逻辑涉及“第几个字符”“截取前 N 个字”,直接用 []byte 下标会出错。
这时候必须转成 []rune,但注意:这会分配新内存,对超长文本要权衡成本。
- 查“第 3 个汉字”:先
r := []rune(s),再r[2] - 用
strings.IndexRune替代strings.Index查单个 Unicode 字符(如 emoji、中文)更准确 - 正则匹配中文推荐用
\p{Han}而非[一-龯],前者覆盖更全且可读性好
strings.Contains 和 strings.Index 就够了;真正需要正则或 Unicode 细粒度控制的部分,往往只占代码的几行——别一上来就堆复杂方案。










