用 substr() 最快最常用,但含中文时必须换 mb_substr(),否则大概率乱码或截半字;substr() 按字节操作,UTF-8 中文占 3 字节,易截断;mb_substr() 需显式指定 'UTF-8' 编码,$start 和 $length 均按字符计数。

直接说结论:用 substr() 最快最常用,但含中文时必须换 mb_substr(),否则大概率乱码或截半字。
为什么 substr() 会把中文截成问号?
因为 substr() 是按字节操作的。UTF-8 中一个中文占 3 字节,substr("你好", 0, 2) 可能只取前 2 字节——这不是完整字符,浏览器就显示 或空格。
- 测试方法:对
"你好世界"执行substr($str, 0, 5),结果常是"你好"(5 字节 ≠ 5 字符) - 安全边界:只有字符串纯 ASCII(如英文、数字、常见符号)时,
substr()的$start和$length才等于“第几个字符” - 别依赖
strlen()判断长度——它也返回字节数,不是字符数
mb_substr() 怎么写才不崩?
四个参数缺一不可:mb_substr($string, $start, $length, 'UTF-8')。漏掉编码或写错值,行为不可控。
- 第四个参数
'UTF-8'必须显式传入,不能省略;系统默认编码可能是ISO-8859-1,一截就空 - 不确定源编码?先用
mb_detect_encoding($str, ['UTF-8', 'GB2312', 'GBK'], true)探测,再传给mb_substr() -
$start = 2表示“从第 3 个 Unicode 字符开始”,不是第 3 个字节;$length = 4就是取 4 个字符,不是 4 字节 - 性能提示:
mb_substr()比substr()慢 3–5 倍,高频循环里慎用(比如日志逐行处理万级数据)
负数 $start 和负数 $length 到底怎么算?
负 $start 从末尾倒数,负 $length 表示“从末尾砍掉多少字符”,两者混用容易误判边界。
-
substr("abcde", -2)→"de"(倒数第 2 个起,到末尾) -
substr("abcde", 1, -1)→"bcd"(从第 1 个起,去掉末尾 1 个) -
substr("abcde", -3, -1)→"cd"(倒数第 3 个起,去掉末尾 1 个) - 危险组合:
substr($str, -2, -5)—— 当$length ≤ $start(都是负数时比较绝对值),$length被强制设为 0,结果永远是空字符串
不是所有“截取”都该用 substr()
硬算位置既难读又易错。遇到分隔符、路径、固定结构,优先选语义化函数。
- 取冒号前内容:
strstr($str, ':', true)(PHP 5.3+,第三个参数true表示返回匹配前部分) - 取文件名:
basename($str)比substr($str, strrpos($str, '/') + 1)更安全,自动处理末尾斜杠 - 取扩展名:
pathinfo($str, PATHINFO_EXTENSION),比substr($str, strrpos($str, '.') + 1)防御更强 - 避免
explode()+array_shift()截取——对空分隔符无保护,且性能差
真正麻烦的从来不是函数怎么调,而是你没想清楚:这个字符串到底是什么编码?目标位置是按字符还是字节定义的?有没有更语义化的替代方案?这些点漏一个,线上就出半个汉字。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











