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

PHP mb_strwidth 寬度計算缺陷與自訂修正函式實作

     編輯:PHP 相關知識

問題背景

專案需依標題像素寬度截斷並加上「...」。初期使用 mb_strimwidth()、mb_strwidth(),發現中文雙引號「 」被判定為寬度 1(半形),實際顯示卻為全形寬度,導致排版錯位。

根因分析

  • 「 」 Unicode 碼位:U+201C、U+201D
  • 屬於 General Punctuation 區塊(U+2000–U+206F)
  • PHP mb_strwidth() 依據 East Asian Width 屬性判定,該區塊字元預設視為半形(寬度 1)
  • 但實際字型渲染多為全形寬度,造成計算與顯示不一致

解決方案:自訂寬度計算函式

逐字檢查,遇 U+2000–U+206F 區塊字元強制計為寬度 2,其餘沿用 mb_strwidth()。

<?php
/**
 * 修正版字串寬度計算:將 U+2000–U+206F 視為全形寬度 2
 */
function amb_strwidth(string $str): int {
    $count = 0;
    $len = mb_strlen($str);
    for ($i = 0; $i < $len; $i++) {
        $ch = mb_substr($str, $i, 1);
        // 正則判斷是否落在 General Punctuation 區塊
        if (preg_match('/[\x{2000}-\x{206F}]/u', $ch)) {
            $count += 2;
        } else {
            $count += mb_strwidth($ch);
        }
    }
    return $count;
}

/**
 * 依指定寬度截斷字串並補上省略號
 */
function truncString(string $str, int $width): string {
    $count = 0;
    $len = mb_strlen($str);
    for ($i = 0; $i < $len; $i++) {
        $ch = mb_substr($str, $i, 1);
        $count += amb_strwidth($ch);
        if ($count > $width) {
            return mb_substr($str, 0, $i) . '...';
        }
    }
    return $str;
}

// 測試
$title = '「PHP 開發」實戰指南';
echo '原始寬度: ' . mb_strwidth($title) . PHP_EOL;      // 可能偏小
echo '修正寬度: ' . amb_strwidth($title) . PHP_EOL;      // 正確
echo '截斷結果: ' . truncString($title, 20) . PHP_EOL;   // 依視覺寬度截斷
?>

進階擴充建議

總結

mb_strwidth() 依 Unicode 標準實作,但實際字型渲染常有出入。針對專案常用標點區塊(如 U+2000–U+206F)客製化修正,能有效解決中文排版截斷錯位問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved