PHP 內建 str_split() 僅支援單位元組字串,對 UTF-8 中文會將一個字符拆成多個位元組,導致錯誤結果。PHP 7.4+ 內建 mb_str_split(),舊版本需自行實作。
<?php
function mbStrSplitRegex($str, $length = 1, $encoding = 'UTF-8') {
if ($length < 1) return false;
// 使用 u 修飾符匹配 Unicode 字符
if ($length === 1) {
// 單字符分割:直接用 preg_split
return preg_split('//u', $str, -1, PREG_SPLIT_NO_EMPTY);
}
// 固定長度分割:正則匹配每 $length 個字符
$pattern = '/(.{' . $length . '})/u';
preg_match_all($pattern, $str, $matches);
$chunks = $matches[1];
// 處理剩餘不足 $length 的字符
$matchedLen = mb_strlen(implode('', $chunks), $encoding);
$totalLen = mb_strlen($str, $encoding);
if ($matchedLen < $totalLen) {
$chunks[] = mb_substr($str, $matchedLen, null, $encoding);
}
return $chunks;
}
?>
<?php
function mbStrSplitLoop($str, $length = 1, $encoding = 'UTF-8') {
if ($length < 1) return false;
$len = mb_strlen($str, $encoding);
$result = [];
for ($i = 0; $i < $len; $i += $length) {
$result[] = mb_substr($str, $i, $length, $encoding);
}
return $result;
}
// 使用
$text = '你好世界 Hello';
print_r(mbStrSplitLoop($text, 3));
/* 輸出:
Array
(
[0] => 你好世
[1] => 界 Hel
[2] => lo
)
*/
?>
<?php
function mbStrSplitWhile($string, $len = 1, $encoding = 'UTF-8') {
if ($len < 1) return false;
$result = [];
$remaining = $string;
while (mb_strlen($remaining, $encoding) > 0) {
$result[] = mb_substr($remaining, 0, $len, $encoding);
$remaining = mb_substr($remaining, $len, null, $encoding);
}
return $result;
}
?>
<?php
function benchmark($func, $str, $len, $iterations = 10000) {
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
$func($str, $len);
}
return microtime(true) - $start;
}
$testStr = str_repeat('中文測試abc', 100); // 900 字符
$len = 10;
echo "Regex: " . benchmark('mbStrSplitRegex', $testStr, $len) . "s\n";
echo "Loop: " . benchmark('mbStrSplitLoop', $testStr, $len) . "s\n";
echo "While: " . benchmark('mbStrSplitWhile', $testStr, $len) . "s\n";
/* 典型結果 (PHP 8.1):
Regex: 0.45s
Loop: 0.38s
While: 0.42s
*/
?>
<?php
// PHP 7.4+ 直接使用
if (function_exists('mb_str_split')) {
$chunks = mb_str_split('你好世界', 2); // ['你好', '世界']
} else {
$chunks = mbStrSplitLoop('你好世界', 2);
}
// 版本相容寫法
function compatMbStrSplit($string, $length = 1, $encoding = 'UTF-8') {
if (function_exists('mb_str_split')) {
return mb_str_split($string, $length, $encoding);
}
return mbStrSplitLoop($string, $length, $encoding);
}
?>
<?php
// 某些字符由多個 Unicode 碼位組成 (如 emoji、帶音調字母)
// 使用 IntlChar (需 intl 擴充) 正確分割
function graphemeSplit($str) {
if (!extension_loaded('intl')) {
return mbStrSplitLoop($str); // 回退
}
$clusters = [];
$len = grapheme_strlen($str);
for ($i = 0; $i < $len; $i++) {
$clusters[] = grapheme_substr($str, $i, 1);
}
return $clusters;
}
$emoji = '👨👩👧👦'; // 家庭 emoji = 7 個碼位但 1 個字素叢集
print_r(mbStrSplitLoop($emoji)); // 錯誤拆分
print_r(graphemeSplit($emoji)); // 正確: ['👨👩👧👦']
?>