PHP 处理中文字符串:长度计算与安全截取函数实现
在 PHP 开发中,处理中文字符串经常面临乱码或截断不完整的问题。虽然 mb_substr 是标准解决方案,但在部分虚拟主机环境中可能未开启。针对此类情况,可以通过正则表达式模拟多字节字符处理逻辑,或编写支持多种常见编码(如 UTF-8、GBK)的通用截取函数,以确保数据在前端的正确展示。
结果或目标
实现无需依赖 mbstring 扩展的中文字符串功能,具体包括:
- 准确统计包含中英文混合字符串的长度。
- 按字符数而非字节数安全截取中文字符串,避免产生半个汉字导致的乱码。
- 兼容 UTF-8、GB2312、GBK 及 Big5 等多种主流中文编码格式。
准备条件
- 运行环境:PHP 7.0 或以上版本(示例代码基于通用语法,兼容性好)。
- 编码规范:建议统一使用 UTF-8 编码保存文件及输出页面,设置 Header 为
header('Content-type:text/html;charset=utf-8');。 - 备选方案认知:若服务器允许,优先检查 php.ini 是否开启了
extension=mbstring,这是最稳妥的方案。
真实操作顺序
第1步:实现自适应长度的中文统计函数
目的:解决无法使用 mb_strlen 时,对中文字符串长度计算不准确的问题。
入口:定义全局函数 abslength。
动作:
- 检查是否存在
mb_strlen函数。若存在,直接调用它并指定'utf-8'编码,保证兼容性。 - 若不存在,使用正则
/./u对字符串进行全局匹配。该正则利用 Unicode 模式u,能正确识别 UTF-8 编码下的多字节字符(包括中文)。 - 统计匹配数组的数量作为长度返回。
/**
* 可以统计中文字符串长度的函数
* @param $str 要计算长度的字符串
* @param $type 计算长度类型,0(默认)表示一个中文算一个字符,1表示一个中文算两个字符
*/
function abslength($str)
{
if(empty($str)){
return 0;
}
if(function_exists('mb_strlen')){
return mb_strlen($str,'utf-8');
} else {
preg_match_all("/./u", $str, $ar);
return count($ar[0]);
}
}
// 测试用例
$str = '我们都是中国人啊,ye!';
$len = abslength($str); // 返回 12
第2步:实现安全的中文截取函数 (UTF-8 专用)
目的:在不使用 mb_substr 的情况下,防止截取到中文汉字的中间字节导致乱码。
入口:定义函数 utf8_substr。
动作:
- 优先检测
mb_substr可用性,若有则直接代理调用。 - 若无可用扩展,使用正则
/./u将字符串拆分为字符数组。 - 使用
array_slice提取指定起始位置$start和长度$end的子数组。 - 使用
join('', ...)将数组重新拼接为字符串返回。
/**
* utf-8编码下截取中文字符串,参数可以参照substr函数
* @param $str 要进行截取的字符串
* @param $start 要进行截取的开始位置,负数为反向截取
* @param $end 要进行截取的长度
*/
function utf8_substr($str,$start=0) {
if(empty($str)){
return false;
}
if (function_exists('mb_substr')){
if(func_num_args() >= 3) {
$end = func_get_arg(2);
return mb_substr($str,$start,$end,'utf-8');
} else {
mb_internal_encoding("UTF-8");
return mb_substr($str,$start);
}
} else {
$null = "";
preg_match_all("/./u", $str, $ar);
if(func_num_args() >= 3) {
$end = func_get_arg(2);
return join($null, array_slice($ar[0],$start,$end));
} else {
return join($null, array_slice($ar[0],$start));
}
}
}
// 测试用例
$str2 = 'wo要截取zhongwen';
echo utf8_substr($str2,0,-4); // 输出: wo要截取zhon
第3步:实现支持多编码的通用中文截取函数
目的:适配老旧系统或不同数据源,支持 GB2312、GBK、Big5 等非 UTF-8 编码的中文截取,并自动追加省略号以防截断。
入口:定义方法 csubstr(可作为类方法或普通函数使用)。
关键参数:
$charset: 指定编码,如 'utf-8', 'gbk'。$suffix: 布尔值,决定是否在末尾添加…。
核心逻辑:
- 定义针对不同编码的正则表达式模式,确保每个正则能精准匹配该编码下的完整字符(包括单字节 ASCII 和多字节中文)。
- 若启用
mb_substr,直接利用其强大的多字节处理能力。 - 若未启用,使用
preg_match_all结合对应编码的正则提取所有字符至数组。 - 对数组进行切片操作,获取目标片段。
- 若
$suffix为真,拼接省略号后返回。
/*
* 中文截取,支持gb2312,gbk,utf-8,big5
*
* @param string $str 要截取的字串
* @param int $start 截取起始位置
* @param int $length 截取长度
* @param string $charset utf-8|gb2312|gbk|big5 编码
* @param bool $suffix 是否加尾缀
*/
function csubstr($str, $start=0, $length, $charset="utf-8", $suffix=true)
{
if(function_exists("mb_substr"))
{
if(mb_strlen($str, $charset) <= $length) return $str;
$slice = mb_substr($str, $start, $length, $charset);
}
else
{
$re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
$re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
$re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
$re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
preg_match_all($re[$charset], $str, $match);
if(count($match[0]) <= $length) return $str;
$slice = join("",array_slice($match[0], $start, $length));
}
if($suffix) return $slice."…";
return $slice;
}
完成判断
通过上述代码部署后,可在 PHP 环境中验证以下状态:
1. var_dump(abslength('测试')) 应正确返回 2。
2. utf8_substr('中文测试', 0, 2) 应输出 '中文' 而非乱码字符。
3. csubstr('这是一段很长的中文内容', 0, 5, 'utf-8') 应输出 '这是一段长…'。
简要总结
在处理中文文本时,避免直接使用原生 substr 是导致乱码的主要原因。利用正则表达式拆解字符或使用内置的多字节函数库,是保障数据完整性的关键。对于生产环境,强烈建议配置好 mbstring 扩展以获取最佳性能和稳定性;对于受限环境,上述提供的正则方案是可靠且高效的替代选择。
以上就是 PHP 中计算中文字符串长度及截取中文字符串的详细内容,更多关于 PHP 字符串处理技巧的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













