PHP 內建 str_split() 按字節分割,UTF-8 中文佔 3 字節會導致亂碼分割。需按字符長度分割(如每 4 個字符一組)。
/**
* 多字節字符串按字符長度分割
* @param string $string 輸入字符串
* @param int $length 每段字符數
* @param string $encoding 編碼(默認 UTF-8)
* @return array 分割後數組
*/
function mbStrSplit($string, $length = 1, $encoding = 'UTF-8') {
if ($length <= 0) return false;
$result = [];
$strLen = mb_strlen($string, $encoding);
for ($i = 0; $i < $strLen; $i += $length) {
$result[] = mb_substr($string, $i, $length, $encoding);
}
return $result;
}
// 測試
$str = '我愛北京3我愛上海-我愛xianggang';
print_r(mbStrSplit($str, 4));
/*
Array
(
[0] => 我愛北京
[1] => 3我愛上
[2] => 海-我愛
[3] => xiang
[4] => gang
)
*/
function graphemeStrSplit($string, $length = 1) {
// \X 匹配一個擴展格拉夫簇(用戶感知的單字符,含組合字符)
preg_match_all('/\X/u', $string, $matches);
$clusters = $matches[0];
return array_chunk($clusters, $length);
}
// 測試組合字符:e + ́ (U+0301) = é
$str = "e\u{0301}clair"; // éclair
print_r(graphemeStrSplit($str, 2));
/*
Array
(
[0] => Array ( [0] => é [1] => c )
[1] => Array ( [0] => l [1] => a )
[2] => Array ( [0] => i [1] => r )
)
*/
function graphemeSplit($string, $length = 1) {
$count = grapheme_strlen($string);
$result = [];
for ($i = 0; $i < $count; $i += $length) {
$result[] = grapheme_substr($string, $i, $length);
}
return $result;
}
| 方案 | 耗時 (ms) | 記憶體 | 備註 |
|---|---|---|---|
| mb_substr 循環 | ~15 | 低 | 通用推薦 |
| preg_match_all /\X/ | ~45 | 中 | 正確處理組合字符 |
| grapheme_* 函數 | ~8 | 低 | 需 intl 擴展,最快 |
mb_internal_encoding('UTF-8'),省去重複傳遞編碼參數。preg_match_all('/\X/u') 獲取格拉夫簇數組,再 array_chunk,語義最準確。intl 擴展使用 grapheme_* 系列。implode 拼接(多字節邊界安全),直接操作數組元素。