应使用mb_substr()函数——它按字符而非字节操作,可避免UTF-8下中文乱码;需显式指定'UTF-8'编码,起始位置从0计,负数表示倒序,配合mb_strlen校验长度更安全。

UTF-8 下一个中文占 3 字节,而 substr() 是纯字节操作函数,这直接导致它无法安全截取含中文的字符串——截的位置稍有偏差,就会把某个中文字符的 3 个字节切开,输出乱码或无效字节序列。
为什么截出来会是乱码
比如字符串 "你好" 在 UTF-8 中实际是 6 个字节:你 → 0xE4 0xBD 0xA0,好 → 0xE5 0xA5 0xBD。
执行 substr("你好", 0, 4) 就只取前 4 个字节:0xE4 0xBD 0xA0 0xE5,
这既不是完整的“你”,也不是完整的“好”,终端或浏览器无法解析,显示为 或其他乱码符号。
常见出错场景
-
按“前 N 个字符”意图截取,却写成
substr($str, 0, N):N=2 时本想取“你好”,结果只拿到“你”的前 2 字节,直接乱码 -
用
strlen()判断长度再截取:strlen("你好")返回 6,但你误以为这是“6 个字符”,用substr($str, 0, 3)想取一半,实际只拿到“你”的第一个字节加后面两个残字节 -
负数偏移也危险:如
substr($str, -1)对英文是取最后一个字母,对中文却大概率只取到某个汉字的最后一个字节,必然乱码
正确做法不是避免,而是换函数
不用硬改逻辑适配字节,而是改用面向字符的函数:
- 用
mb_substr($str, 0, 2, 'UTF-8')—— 明确按“字符数”截,2就是“你好”两个字 - 用
mb_strlen($str, 'UTF-8')替代strlen()获取真实字符长度 - 务必显式传入
'UTF-8'编码参数,不依赖默认值,避免环境差异引发问题
补充说明:不是所有中文都严格占 3 字节
绝大多数简体中文在 UTF-8 中确实是 3 字节,但生僻字、emoji、繁体扩展字可能占 4 字节(如某些 Unicode 补充平面字符)。substr 在这类情况下错得更隐蔽,而 mb_substr 仍能正确识别为单个字符处理。

















