登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  Golang >  Go问答

Go unicode/utf8.RuneCountInString 怎么判断字符数:字节长度、中文文本与截断边界

来源:17golang原创

时间:2026-08-30 12:59:35 406浏览 收藏

接口返回“最多 4 个字符”时,直接写 s[:4] 很容易把中文或 emoji 切成半个 UTF-8 序列。Go 的 len 统计的是字节,unicode/utf8.RuneCountInString 统计的是 UTF-8 解码后的 rune 数;两者回答的不是同一个问题。

要点速览
  • len(s) 适合判断传输字节数,不适合当作中文字符数。
  • utf8.RuneCountInString(s)range 的计数一致,适合做 rune 数量判断。
  • 按字符截断应沿着 rune 起始位置切片,不能按字节下标硬切。
  • 非法 UTF-8 仍会被计为 rune,但入库或对外输出前应先用 utf8.ValidString 检查。

先看一个字符串为什么会有三种长度

同一段 Go语言🚀,字节长度、rune 数和用户眼中的“字符”可能不同。下面的程序故意把这三个概念放在同一行输出,先别急着改业务代码,看看实际结果。

text := "Go语言🚀"
fmt.Printf("bytes=%d runes=%d range=%d valid=%t\n",
    len(text), utf8.RuneCountInString(text), countRange(text), utf8.ValidString(text))
Go 终端显示 Go语言和 emoji 的字节数、rune 数与有效性结果
图1:核对同一字符串的 bytes、runes 和 range 结果;三项一致说明计数口径已经分开。

运行结果中,ASCII 字母占 1 个字节,中文通常占 3 个字节,emoji 可能占 4 个字节。因此 len 会随编码字节数增长,而 RuneCountInString 只按解码出的 rune 计数。官方文档也把它定义为 string 版本的 RuneCount

RuneCountInString 和 range 到底该信谁

如果只是判断“是否超过 20 个 rune”,直接调用 utf8.RuneCountInString 最清楚;如果还要逐个检查字符、过滤或拼接,range 更自然。两者都按 UTF-8 解码规则前进,并不等同于用户感知的字素簇数量。

写法统计对象适合场景
len(s)字节协议、文件、请求体大小
utf8.RuneCountInString(s)rune长度校验、配额和日志字段
for range s逐 rune 遍历过滤、转换、按 rune 截断

按字符截断时,边界要落在 rune 起点

安全截断的关键不是把字符串转成 []rune 后永远复制一份,而是沿着 range 提供的字节下标切片。示例中的 truncateRunes 在达到上限时使用当前 rune 的起始位置,因此不会把中文或 emoji 拆开。

func truncateRunes(s string, limit int) string {
    if limit 
Go 终端显示按 rune 截断后的结果以及非法 UTF-8 的校验结果
图2:观察 cut-4 没有半个中文或 emoji,并对照 invalid 的字节数、rune 数和 valid=false。

这里的“字符数”仍然是 rune 数。像组合音标或某些旗帜 emoji,可能由多个 rune 组成一个用户感知字符;需要按字素簇截断时,应选择专门的 Unicode 文本处理库,而不是把 RuneCountInString 当成 UI 字符数。

非法 UTF-8 要不要先拦截

RuneCountInString 不会替你完成输入合法性校验。对于非法或不完整编码,UTF-8 解码会用 RuneError 处理并按一个字节前进,所以“计数成功”不代表内容适合入库。网络边界、文件读取和用户提交的文本,建议先判断 utf8.ValidString,再决定拒绝、替换还是记录。

if !utf8.ValidString(input) {
    return fmt.Errorf("input is not valid UTF-8")
}

常见问题

len(string) 能不能直接当中文长度?

不能。它返回 UTF-8 字节数;中文、emoji 等多字节内容会让结果大于 rune 数。

RuneCountInString 会统计用户看到的 emoji 数吗?

它统计 rune,不保证等于字素簇数量。复杂 emoji 或组合字符要用字素簇规则处理。

直接 s[:limit] 为什么可能出现乱码?

limit 可能落在多字节 rune 的中间,切片后形成非法 UTF-8;应按 range 的字节起点截断。

非法 UTF-8 的 RuneCountInString 会报错吗?

不会返回错误;它会按解码规则计数。需要严格输入时,另行调用 utf8.ValidString

把长度口径写进接口契约

如果字段限制按字节,接口文档就写清楚字节上限;如果按 rune,使用 RuneCountInString 并补上非法 UTF-8 策略;如果按用户看到的字符,则需要明确字素簇规则。把这三个口径分开,通常比在校验失败后猜“Go 的字符串长度为什么不对”更省时间。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>