必须用 rune 遍历字符串才能正确识别 Emoji,因 Go 的 string 是字节序列,直接按 byte 遍历会破坏多字节 Emoji;Emoji 主要分布在 U+1F600–U+1F64F、U+1F300–U+1F5FF、U+1F1E6–U+1F1FF、U+1F900–U+1F9FF 等 Unicode 区间。

用 rune 遍历判断是否含 Emoji Unicode 范围
Go 的 string 是字节序列,直接按 byte 遍历会切碎多字节的 Emoji(比如 ?? 占 4 字节),必须转成 rune 才能正确识别单个字符。Emoji 大多落在 Unicode 的特定区间,如基本 Emoji(U+1F600–U+1F64F)、旗帜(U+1F1E6–U+1F1FF)、符号(U+1F900–U+1F9FF)等。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
for _, r := range str遍历rune,别用for i := range str - 检查每个
r是否落在常见 Emoji 区间内,例如:func isEmoji(r rune) bool { return (r >= 0x1F600 && r <= 0x1F64F) || // emoticons (r >= 0x1F300 && r <= 0x1F5FF) || // symbols & pictographs (r >= 0x1F1E6 && r <= 0x1F1FF) || // flags (r >= 0x1F900 && r <= 0x1F9FF) // supplemental symbols } - 注意:Unicode 标准持续更新,新版 Go(如 1.22+)的
unicode包仍不内置完整 Emoji 判定,不能依赖unicode.IsSymbol或unicode.IsMark—— 它们会漏判或误判
过滤 Emoji 时保留合法中文、英文、数字和标点
单纯删掉所有非 ASCII 字符会误伤中文、日文、韩文、带重音的拉丁字母(如 naïve)、甚至某些数学符号。过滤目标应是「仅移除 Emoji 类字符」,而非「只留 ASCII」。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 构建白名单逻辑比黑名单更安全:先定义允许的字符范围(如
unicode.Letter、unicode.Digit、unicode.Punct、unicode.Space),再额外排除已知 Emoji 区间 - 避免用
strings.Map直接映射删除 —— 它对组合型 Emoji(如 ??)无效,因为这类是多个rune组合(ZJW + VS16),需做连贯性检测 - 简单场景下可先用
isEmoji过滤单个rune;若需处理家庭/职业类组合 Emoji(????),就得引入第三方库如github.com/mvdan/xurls/v2或github.com/elliotchance/emoji,它们做了组合序列解析
性能敏感场景下避免重复编译正则或遍历多次
有人用正则匹配 Emoji(如 [\u1f600-\u1f64f\u1f300-\u1f5ff...])再 Regexp.ReplaceAllString,但每次调用都隐式编译(除非预编译为全局 *regexp.Regexp),且正则在 Unicode 范围匹配上不如 rune 遍历稳定。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 预编译正则仅当必须支持复杂模式(如“保留国旗但删表情”)时才考虑;否则直接
rune循环 + 条件判断更快、内存更省 - 不要在循环里反复调用
utf8.RuneCountInString或strings.Split—— 它们会重新扫描整个字符串 - 如果要批量处理大量文本,把过滤逻辑封装成
func(string) string并复用,避免闭包捕获大对象
测试时特别注意组合型 Emoji 和零宽连接符
像 ?(U+1F4AA)是单个 rune,但 ??(U+1F468 U+200D U+1F4BB)是 3 个 rune:人 + ZWJ + 笔记本。标准 isEmoji(r) 会放过中间的 0x200D(ZWJ),导致残留乱码或截断。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 单元测试至少覆盖:
"Hello ?"、"??"、"?? + ??"、"test??"(带肤色修饰符)、"\u200d"(单独 ZWJ) - 对组合序列,需向前/向后扫描:遇到 ZWJ(
0x200D)、VS15/VS16(0xFE0E/0xFE0F)、修饰符(0x1F3FB–0x1F3FF)时,整组视为一个 Emoji 单元处理 - 真要高保真过滤,别自己造轮子 —— 用
github.com/elliotchance/emoji的FindAllString先提取,再按需剔除
Emoji 的边界比看上去模糊得多:同一个符号在不同系统渲染效果不同,Unicode 标准每年底更新,而 Go 的 unicode 包更新滞后。最稳妥的做法不是追求 100% 精确识别,而是明确业务容忍度——比如只要求干掉 95% 明显 Emoji,且不破坏其他文字,那就用基础 rune 区间判断足矣;一旦涉及社交产品评论、昵称审核等场景,就得引入专业 emoji 库并定期更新规则。


















