微博字數規則:中文 2 分、英文 1 分、全角標點 2 分、半角標點 1 分。PHP strlen 計位元組(UTF-8 中文 3 字節),mb_strlen 計字符(中文 1 個),均不符合。本文提供精準實現 strlen_weibo(),支援 UTF-8 與 GBK 雙編碼。
/**
* 微博風格字符長度計算
* @param string $string 輸入字符串
* @param string $charset 編碼:'utf-8' 或 'gbk'
* @return int 計算長度
*/
function strlen_weibo(string $string, string $charset = 'utf-8'): int {
$n = $count = 0;
$length = strlen($string);
$charset = strtolower($charset);
if ($charset === 'utf-8') {
while ($n < $length) {
$byte = ord($string[$n]);
// ASCII 控制字符、可打印字符(含半角標點、數字、字母)
if ($byte === 9 || $byte === 10 || (32 <= $byte && $byte <= 126)) {
$n++; $count++;
}
// 2 字節 UTF-8 字符(擴展拉丁、希臘、西里爾等)→ 視為 2 分
elseif (194 <= $byte && $byte <= 223) {
$n += 2; $count += 2;
}
// 3 字節 UTF-8(中日韓統一表意文字、常用漢字)→ 2 分
elseif (224 <= $byte && $byte <= 239) {
$n += 3; $count += 2;
}
// 4 字節 UTF-8(Emoji、生僻字)→ 2 分
elseif (240 <= $byte && $byte <= 247) {
$n += 4; $count += 2;
}
// 5/6 字節(極罕見,保守按 2 分)
elseif (248 <= $byte && $byte <= 251) {
$n += 5; $count += 2;
}
elseif ($byte === 252 || $byte === 253) {
$n += 6; $count += 2;
}
// 非法字節,按 1 字節跳過計 1 分
else {
$n++; $count++;
}
if ($count >= $length) break; // 安全閾值
}
return $count;
}
// GBK/GB2312:雙字節字符高位 ≥ 0x81
for ($i = 0; $i < $length; $i++) {
if (ord($string[$i]) > 127) {
$i++; // 跳過低位字節
$count++; // 雙字節字符計 1 個「中文單位」→ 2 分
}
$count++; // ASCII 或已計數的雙字節字符各計 1 分
}
return $count;
}
<?php
$str = "s@@你好"; // s(半角) @(全角) @(半角) 你(中) 好(中)
var_dump(strlen_weibo($str, 'utf-8')); // int(8)
// 解析:s=1, @=2, @=1, 你=2, 好=2 → 總計 8
| 首字節範圍 | 字節數 | 字符集範例 | 微博計分 |
|---|---|---|---|
| 0x00-0x7F (0-127) | 1 | ASCII 控制/可打印 | 1 |
| 0xC2-0xDF (194-223) | 2 | 拉丁擴展、希臘、西里爾 | 2 |
| 0xE0-0xEF (224-239) | 3 | 中日韓統一表意文字 (CJK) | 2 |
| 0xF0-0xF7 (240-247) | 4 | Emoji、CJK 擴展 A/B | 2 |
| 0xF8-0xFB (248-251) | 5 | 極罕見 | 2 |
| 0xFC-0xFD (252-253) | 6 | 理論最大 | 2 |
0x81-0xFE(即 > 127)。class WeiboLength {
public static function calc(string $str, string $charset = 'utf-8'): int {
return strlen_weibo($str, $charset);
}
// 截取至指定微博長度(返回截取後字符串)
public static function substr(string $str, int $maxLen, string $charset = 'utf-8', string $suffix = '...'): string {
// 此處需配合字符級截取(如 mb_substr 或自定義),略
}
}
gbk 會產生錯誤計數,務必確保編碼一致。👨👩👧👦 (家庭) 由多個代碼點組成,本函數按字節級處理會計為多個 2 分單位,實際顯示為 1 個字形。需用 grapheme_strlen (intl 擴展) 處理字形簇。精準掌握字符寬度計算,是構建輸入限制、顯示截斷、排版引擎的基石,微博風格只是其中一種業務規則映射。