strings.count 是 go 中按字节匹配统计子串出现次数的函数,支持 utf-8 编码的中文、emoji 等,但不按 rune 解码,也不支持重叠匹配;空子串恒返回 0。

strings.Count 是什么,能统计中文或 Unicode 字符吗
strings.Count 是 Go 标准库中用于统计子字符串在目标字符串中出现次数的函数,定义在 strings 包里。它只做「子串匹配计数」,不区分字符编码,按字节(byte)逐位扫描 —— 这意味着它对 UTF-8 编码的中文、emoji 等多字节字符完全可用,但前提是传入的子串本身是合法的 UTF-8 片段。
常见误解是以为它“按 rune 统计”,其实不是:strings.Count 不会解码 UTF-8,它只是暴力比对字节序列。只要 substr 是目标字符串的连续字节子序列,就能正确计数。
- ✅
strings.Count("你好世界你好", "你好")返回2 - ✅
strings.Count("a?b?c", "?")返回2(emoji ? 是 4 字节 UTF-8 序列) - ❌
strings.Count("你好", "你")中若"你"被错误拼成非 UTF-8 字节(如截断的前 2 字节),会返回0—— 不报错,但匹配失败
为什么 strings.Count("", "a") 返回 0,而 strings.Count("a", "") 返回 0?
空字符串作为子串时,strings.Count 的行为有明确定义:无论主串是否为空,只要 substr == "",结果恒为 0。这不是 bug,而是标准实现逻辑 —— Go 认为空字符串“不构成可计数的匹配单位”。
这个设计避免了语义歧义:比如 "ab" 中空字符串理论上可插入在每个位置(开头、a 后、b 后、结尾),共 3 处,但 strings.Count 不采用这种数学上的“间隙计数”模型。
- ⚠️ 别写
if substr == "" { return len(s) + 1 }这类自定义逻辑,和标准库行为不一致,后续维护易出错 - ⚠️ 如果业务真需要“间隙数”,应单独封装,例如:
func countEmptyGaps(s string) int { return utf8.RuneCountInString(s) + 1 } - ✅ 正常使用时,确保
substr非空,否则直接跳过调用
性能敏感场景下,Count 和自己遍历 rune 有什么区别
对纯 ASCII 字符串,strings.Count 极快 —— 它用汇编优化的字节查找(如 memclr 相关底层指令),时间复杂度接近 O(n);而手动用 range 遍历 rune,先解码再匹配,至少多一次 UTF-8 解码开销,且无法利用 CPU 的 SIMD 加速。
但注意:如果子串长度 > 1,且你只关心单个 Unicode 字符(如统计某个汉字出现次数),strings.Count 仍是更优选择 —— 它内部做了 Boyer-Moore 类优化,比逐 rune 比对更快。
- ✅ 推荐:统计任意子串(包括单字符、多字符、emoji)→ 无脑用
strings.Count - ⚠️ 不推荐:为统计单字符而写
for _, r := range s { if r == '你' { cnt++ } }—— 更慢,且无法处理 emoji(emoji 是单个rune,但range没问题;真正问题是冗余) - ⚠️ 注意:若需同时获取位置索引,
strings.Count不提供,得换strings.Index循环或strings.FieldsFunc
strings.Count 无法处理重叠匹配怎么办
strings.Count 默认不支持重叠匹配。例如 strings.Count("aaaa", "aa") 返回 2(匹配位置 0 和 2),而不是 3(0、1、2)。这是由其实现决定的:每次匹配后直接跳过整个匹配长度。
如果业务需要重叠计数(比如密码强度检测中统计连续重复字符),必须手写循环:
func countOverlap(s, substr string) int {
if len(substr) == 0 {
return 0
}
cnt := 0
for i := 0; i
- ⚠️
s[i:i+len(substr)]可能 panic,务必提前检查len(s) >= len(substr) - ✅ 对小字符串够用;大数据量建议用
bytes.Index循环 + 偏移 1,避免反复切片 - ⚠️ 别试图用正则(
regexp)替代 —— 开销大,且默认也不重叠;FindAllStringIndex同样非重叠
重叠匹配是少数需要绕过 strings.Count 的真实场景,但发生频率不高。多数时候,明确“非重叠”才是语义正确的默认行为。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











