mb_strlen 返回字符数而 strlen 返回字节数,UTF-8 中一个汉字占3字节但算1字符;未指定编码或编码不匹配会导致 mb_substr 乱码;mb_detect_encoding 不可靠,应明确源头编码并用 mb_check_encoding 验证。

mb_strlen 为什么返回的长度和 strlen 不一样
因为 strlen 按字节计数,而中文、日文等多字节字符(如 UTF-8 下的汉字)通常占 3 个字节,strlen 就会把一个汉字算成 3;mb_strlen 按字符计数,默认使用当前 mb_internal_encoding() 编码(通常是 UTF-8),所以一个汉字算 1。
常见错误:用 strlen 截取中文字符串导致乱码或截断不完整。
- 务必确认当前内部编码:
echo mb_internal_encoding(); // 应为 UTF-8
- 显式指定编码更安全:
mb_strlen($str, 'UTF-8')
- 如果输出是 GBK 页面,但源数据是 UTF-8,需先转换再计算:
mb_strlen(mb_convert_encoding($str, 'UTF-8', 'GBK'), 'UTF-8')
mb_substr 截取中文时出现乱码或空字符
根本原因是没传编码参数,或编码与实际不符。PHP 7.2+ 默认使用 mb_internal_encoding(),但旧版本或某些 SAPI(如 CLI)可能默认是 ISO-8859-1,导致 mb_substr($str, 0, 5) 拿到半个 UTF-8 字节序列,解码失败就变空或 。
- 永远显式传第三个参数:
mb_substr($str, 0, 5, 'UTF-8')
- 避免依赖全局设置,尤其在 CLI 或多编码混合项目中
- 注意:起始位置和长度单位都是「字符」,不是字节 ——
mb_substr($str, 0, 2, 'UTF-8')取前两个汉字,不是前两个字节
mb_detect_encoding 不可靠,别拿来判断编码
mb_detect_encoding 是启发式猜测,对短文本、纯 ASCII 或混合编码几乎必然误判。比如一段含中文的 JSON 字符串,可能被错判为 SJIS 或 EUC-JP,后续 mb_convert_encoding 就会把 UTF-8 字节当其他编码转,结果全乱。
本文档主要讲述的是Ruby on Rails字符串处理;在Ruby中创建一个字符串有多种方式。可以有两种方式表示一个字符串:用一对单引号包围字符('str')或用一对双引号包围字符("str") 这两种形式的区别在于对于包围的字符串的处理,用双引号构造的字符串能处理更多的转移字符。 希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看
立即学习“PHP免费学习笔记(深入)”;
- 真实项目中应**明确知道输入编码**,从源头控制(HTTP 请求头、数据库连接 charset、文件保存格式)
- 若必须检测,至少限定候选集并设 strict:
mb_detect_encoding($str, ['UTF-8', 'GBK', 'BIG5'], true)
- 更稳妥的做法是用
mb_check_encoding($str, 'UTF-8')验证,返回 false 就说明不是合法 UTF-8,再考虑 fallback 处理
开启 mbstring 扩展后 mb_ 函数仍报 undefined
常见于 Docker 环境、自编译 PHP 或某些云函数平台 —— 扩展虽已安装,但未启用或被禁用函数列表屏蔽。
- 检查是否启用:
php -m | grep mbstring
或var_dump(extension_loaded('mbstring')); - 确认
disable_functions里没禁用mb_substr等(查看phpinfo()中 “Disabled Functions” 行) - 某些 Alpine Linux 镜像需额外装
php-mbstring包(不止是php主包) - CLI 和 Web SAPI 的 php.ini 可能不同,用
php --ini和phpinfo()分别确认










