Go以rune为单位处理Unicode,len()返回字节数而非字符数,故len("??")为4;正确获取字符数需转[]rune;遍历、切分、正则等操作须注意Unicode支持。

Go 原生以 rune 为单位处理 Unicode,字符串字面量默认 UTF-8 编码,但直接用 len() 或下标访问会按字节而非字符出错——这是绝大多数新手踩坑的根源。
为什么 len("??") 返回 4 而不是 1
Go 的 string 是只读字节序列,len() 返回 UTF-8 字节数。表情符号 "??" 是由多个 Unicode 码点(含 ZWJ 连接符)组成的合成字符,在 UTF-8 中占 4 个字节,所以 len() 返回 4。这不是 bug,是设计使然。
正确做法是转成 []rune 后再取长度:
str := "??" fmt.Println(len(str)) // 4 —— 字节数 fmt.Println(len([]rune(str))) // 1 —— 字符数(rune 数)
遍历字符串时别用 for i := 0; i
这种写法会把多字节字符拆开,导致乱码或 panic(越界)。
立即学习“go语言免费学习笔记(深入)”;
- ❌ 错误:按字节索引遍历
s[i],可能截断 UTF-8 序列 - ✅ 正确:用
range遍历,自动解码为rune - ✅ 替代:显式转
[]rune再用下标(适合需随机访问的场景)
示例对比:
s := "Go语言"
for i, r := range s {
fmt.Printf("index %d: rune %U (%c)\n", i, r, r)
}
// 输出:
// index 0: U+0047 (G)
// index 2: U+006F (o)
// index 4: U+8BED (语)
// index 7: U+8A00 (言)
// 注意:i 是字节偏移,不是字符序号
截取子串必须用 []rune 转换后再操作
直接用 s[0:3] 是按字节切,极大概率破坏 UTF-8 编码。例如 "你好"[0:2] 会得到非法字节序列,打印显示为 ""。
本文档主要讲述的是Ruby on Rails字符串处理;在Ruby中创建一个字符串有多种方式。可以有两种方式表示一个字符串:用一对单引号包围字符('str')或用一对双引号包围字符("str") 这两种形式的区别在于对于包围的字符串的处理,用双引号构造的字符串能处理更多的转移字符。 希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
安全截取前 N 个字符的写法:
s := "Hello世界?"
n := 5
runes := []rune(s)
if n > len(runes) {
n = len(runes)
}
result := string(runes[:n]) // ✅ 正确:先转 rune 切片,再转回 string
注意:string([]rune(s)[:n]) 是常见惯用法,但对超长字符串有内存开销——如果只取前几个字符且原串极大,可考虑用 utf8.DecodeRuneInString 手动解码避免全量转换。
正则匹配中文、emoji 等需启用 Unicode 模式
regexp 包默认不识别 Unicode 字符类(如 \p{Han}),必须使用 (?U) 标志或 \p{...} 语法:
re := regexp.MustCompile(`(?U)\p{Han}+`) // 匹配汉字
re.FindAllString("Hello你好World", -1) // → ["你好"]
re2 := regexp.MustCompile(`\p{Emoji}\p{Emoji_Modifier}?`)
re2.FindAllString("????", -1) // → ["??", "??"]
漏掉 (?U) 或写成 \w+ 会完全匹配不到中文/emoji,因为 \w 只覆盖 ASCII 字母数字下划线。
最易被忽略的是:字符串拼接、格式化(fmt.Sprintf)、JSON 编解码本身都支持 UTF-8,无需额外处理;真正要动手的地方只有「长度计算」「索引访问」「子串切分」「正则匹配」这四类操作——其余时候,放心当它是个普通字符串用就行。









