发布于2026-07-14 阅读(0)
扫一扫,手机访问
先说一个很多新手容易踩的坑:用 len() 去统计中英文混合字符串的字符数,结果往往不对——因为 len() 本身是按字节来算的,不会管你字符边界。在 UTF-8 编码下,中文字符占 3 个字节,英文字符占 1 个字节,所以 len("你好hello") 返回 9,但实际只有 7 个字符(2 个中文 + 5 个英文)。如果直接用 len() 做截断或索引,很容易出现乱码,甚至越界。

len() 不能直接用在中英文混合字符串上一句话总结:len() 返回的是字节长度,不是字符(rune)数量。中文字符在 UTF-8 编码下占 3 个字节,英文和 ASCII 字符占 1 个字节,所以 len("你好hello") 是 9,但实际只有 7 个字符(2 个中文 + 5 个英文)。误用 len() 会导致截断、索引越界或显示异常。这是很多刚接触 Go 的同学最容易翻车的地方。
utf8.RuneCountInString 是最简单可靠的计数方式那怎么办呢?直接调用 utf8.RuneCountInString 就对了。它做的事情很简单:遍历每个 rune,统计 Unicode 码点个数,无论中文、英文、emoji 还是全角符号,都能准确计数。而且它不需要手动转换为 []rune,避免了额外的内存分配,性能也足够好。
常见用法:
count := utf8.RuneCountInString("你好world?") // 返回 8len([]rune(s)) 更轻量utf8.RuneCountInString 和 strings.Count 混用但要注意,别把 RuneCountInString 和 strings.Count 弄混了。strings.Count 是统计子串出现次数的,跟字符数完全是两码事;而 utf8.RuneCountInString 只认 rune 边界,不关心内容。例如:
立即学习“go语言免费学习笔记(深入)”;
utf8.RuneCountInString("??") // 返回 1(尽管底层是多个 UTF-8 码元,但它是单个合成 emoji)
容易踩的坑:
nil 字符串会 panic —— 实际中应先判空:if s == "" { return 0 }utf8.DecodeRuneInString 或 for range最后再提一个常见场景:如果既要计数,又要安全截断前 N 个字符,那 RuneCountInString 就帮不上忙了,因为它只负责计数,不告诉你字节偏移。这时候不能靠字节切片,否则会破坏 UTF-8 编码。正确的做法是使用 for range 循环手动推进:
s := "Hello世界?"n := 5runeCount := 0for i, r := range s { if runeCount >= n { s = s[:i] break } runeCount++}
或者用 utf8.DecodeRuneInString 手动推进,但 for range 更直观可靠。记住:字符串不可变,任何“截取”都要生成新字符串,且起止位置必须落在 rune 边界上。
真正麻烦的是既要计数又要截断还要兼容 emoji 组合——这时候别硬写循环,考虑用 golang.org/x/text/unicode/norm 做标准化,或者引入成熟库如 runewidth 处理显示宽度。但单纯字符计数,utf8.RuneCountInString 就够了,别绕远路。