len() 不能直接用于统计中文字符串字数,因为它返回字节长度而非字符数;“你好”在 utf-8 中占 6 字节,但只有 2 个字符;应使用 utf8.runecountinstring() 获取正确字符数。

为什么 len() 不能直接用在中文字符串上
Go 的 len() 返回的是字节长度,不是字符(rune)个数。一个中文汉字在 UTF-8 编码下占 3 个字节,所以 len("你好") 得到的是 6,而不是 2。如果你要统计“字数”(即人眼感知的字符个数),必须按 rune 计数。
用 utf8.RuneCountInString() 最简单可靠
标准库 unicode/utf8 提供了专为此场景设计的函数,它遍历字符串并正确识别每个 Unicode 码点(包括中文、emoji、全角符号等),无需手动转 []rune。
实操建议:
- 直接调用
utf8.RuneCountInString(s),性能好、内存零分配 - 不要写
len([]rune(s))—— 这会额外分配切片,对长字符串有明显开销 - 注意:该函数对非法 UTF-8 字节序列会返回负数,但实际中只要输入是合法字符串(如从
string字面量、HTTP body 解析或文件读取后未篡改),基本不会触发
import "unicode/utf8"
func ChineseCharCount(s string) int {
return utf8.RuneCountInString(s)
}
需要区分“中文字符”和其他字符?得用 unicode.Is(unicode.Han, r)
如果需求是“只统计汉字”,而非所有 Unicode 字符(比如想排除标点、英文字母、数字),就得逐个 rune 判断。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
常见错误现象:
- 用
r >= '一' && r 手动区间判断 —— 汉字分散在多个 Unicode 区段(如扩展 A/B/C),漏判严重 - 用
unicode.IsLetter(r)—— 会把英文字母、日文假名也计入
正确做法是用 unicode.Is(unicode.Han, r),它覆盖全部汉字区(含部首、康熙字典部件等):
import (
"unicode"
"unicode/utf8"
)
func HanCharCount(s string) int {
count := 0
for _, r := range s {
if unicode.Is(unicode.Han, r) {
count++
}
}
return count
}
性能和边界情况提醒
两个函数在绝大多数场景都够用,但要注意:
-
utf8.RuneCountInString()是 O(n) 时间、O(1) 空间,比len([]rune(s))快且省内存 - emoji 如
"?"或"??"算作 1 个rune(基础 emoji),但 ZWJ 组合 emoji(如后者)实际由多个rune构成,RuneCountInString仍返回其组成码点数(不是“视觉字数”);若需真正意义上的“显示字数”,得用专门的 emoji 库(如github.com/maragudk/gomoji) - 空字符串、纯 ASCII、混合中英文——这些都没问题,函数本身无须额外 guard
真正容易被忽略的是:你到底要“UTF-8 字符数”还是“严格汉字数”。前者用 RuneCountInString,后者必须遍历 + unicode.Is(unicode.Han, r),别混用。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










