在 PHP 開發中,中文字符串截取是常見需求,但因編碼差異(GB2312、UTF-8 等),直接使用 substr 會導致亂碼。本文匯總四種主流截取方案,涵蓋不同編碼場景,助你輕鬆應對多字節字符處理。
針對 GB2312 編碼,利用 ord() 判斷字節高位(> 0xA0)識別雙字節漢字,逐字符拼接:
function mysubstr($str, $start, $len) {
$tmpstr = '';
$strlen = $start + $len;
for ($i = 0; $i < $strlen; $i++) {
if (ord(substr($str, $i, 1)) > 0xA0) {
$tmpstr .= substr($str, $i, 2);
$i++;
} else {
$tmpstr .= substr($str, $i, 1);
}
}
return $tmpstr;
}
適用場景:舊系統維護、GB2312 編碼項目。
使用正則表達式匹配 UTF-8 多字節模式(ASCII 1 字節、雙字節、三字節等),配合 preg_replace 精準截取:
function utf8Substr($str, $from, $len) {
return preg_replace(
'#^(?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$from.'}'.
'((?:[\x00-\x7F]|[\xC0-\xFF][\x80-\xBF]+){0,'.$len.'}).*#s',
'$1', $str
);
}
優點:代碼簡潔;缺點:正則複雜,效能稍遜於逐字符解析。
整合 UTF-8 與 GB2312 支援,通過 preg_match_all 將字符串拆分為字符陣列,再用 array_slice 截取,自動補充省略號:
function cut_str($string, $sublen, $start = 0, $code = 'UTF-8') {
if ($code === 'UTF-8') {
$pa = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|\xe0[\xa0-\xbf][\x80-\xbf]|[\xe1-\xef][\x80-\xbf][\x80-\xbf]|\xf0[\x90-\xbf][\x80-\xbf][\x80-\xbf]|[\xf1-\xf7][\x80-\xbf][\x80-\xbf][\x80-\xbf]/";
preg_match_all($pa, $string, $t_string);
$slice = array_slice($t_string[0], $start, $sublen);
return count($t_string[0]) - $start > $sublen
? join('', $slice) . '...'
: join('', $slice);
} else { // GB2312
$start *= 2; $sublen *= 2;
$strlen = strlen($string);
$tmpstr = '';
for ($i = 0; $i < $strlen; $i++) {
if ($i >= $start && $i < ($start + $sublen)) {
$tmpstr .= ord(substr($string, $i, 1)) > 129
? substr($string, $i, 2)
: substr($string, $i, 1);
}
if (ord(substr($string, $i, 1)) > 129) $i++;
}
return strlen($tmpstr) < $strlen ? $tmpstr . '...' : $tmpstr;
}
}
// 測試
$str = "abcd需要截取的字符串";
echo cut_str($str, 8, 0, 'gb2312'); // 輸出:abcd需要截...
核心優勢:單一函數兼容雙編碼,邏輯清晰,生產環境推薦使用。
源自 BugFree 開源項目,專為 UTF-8 設計,逐字符判斷字節長度(1~3 字節),支援可選省略號:
function sysSubStr($String, $Length, $Append = false) {
if (strlen($String) <= $Length) return $String;
$I = 0; $StringLast = [];
while ($I < $Length) {
$StringTMP = substr($String, $I, 1);
if (ord($StringTMP) >= 224) { $StringTMP = substr($String, $I, 3); $I += 3; }
elseif (ord($StringTMP) >= 192) { $StringTMP = substr($String, $I, 2); $I += 2; }
else { $I++; }
$StringLast[] = $StringTMP;
}
$StringLast = implode('', $StringLast);
return $Append ? $StringLast . '...' : $StringLast;
}
cut_str 或 PHP 內建 mb_substr(需啟用 mbstring 擴展)。掌握這些方案,即可從容應對各類中文截取需求,告別亂碼困擾。