首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 多位元組字串分割函數 mb_str_split 實作與優化

     編輯:PHP 綜合知識

問題背景

PHP 內建 str_split() 僅支援單位元組字串,對 UTF-8 中文會將一個字符拆成多個位元組,導致錯誤結果。PHP 7.4+ 內建 mb_str_split(),舊版本需自行實作。

實作方案一:正則分割 (PHP 5.6+)

<?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;
}
?>

實作方案二:mb_substr 迴圈 (相容性最好)

<?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
)
*/
?>

實作方案三:while 迴圈 (避免 mb_strlen 重複呼叫)

<?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 7.4+ 內建函數使用

<?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);
}
?>

應用場景

  • 中文分詞預處理:固定窗口特徵提取
  • 文字遊戲/驗證碼:隨機打亂字符順序
  • 編碼轉換:逐字符處理 (如 Base64、URL 編碼)
  • 版面排版:按字符數換行、截斷顯示
  • 密碼強度檢查:逐字符分析字符類型分佈

進階:支援 Grapheme Cluster (組合字符)

<?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));       // 正確: ['👨‍👩‍👧‍👦']
?>
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved