正則匹配中文是表單驗證、內容過濾、數據清洗的高頻需求。但 GBK 與 UTF-8 編碼下中文匹配模式截然不同,搞混極易導致匹配失效或誤傷。本文系統整理雙編碼下的中文正則模式與實戰代碼。
| 編碼 | 中文編碼範圍 | 字節數 | 正則策略 |
|---|---|---|---|
| GBK/GB2312 | 高位字節 0x81-0xFE,低位 0x40-0xFE(除 0x7F) | 雙字節 | 按字節範圍匹配:[\x81-\xFE][\x40-\xFE] |
| UTF-8 | 基本多文種平面 (BMP) 中日韓統一表意文字:U+4E00-U+9FA5 | 三字節 | 按 Unicode 碼點匹配:[\x{4e00}-\x{9fa5}] 需 u 修飾符 |
<?php
$str = '全部是漢字測試';
// ^ 開頭 $ 結尾 + 一次或多次
if (preg_match('/^([\x81-\xFE][\x40-\xFE])+$/', $str)) {
echo '全部是漢字';
} else {
echo '不全是漢字';
}
// 輸出:全部是漢字
$str2 = 'all全部是漢字測試';
if (preg_match('/^([\x81-\xFE][\x40-\xFE])+$/', $str2)) {
echo '全部是漢字';
} else {
echo '不全是漢字';
}
// 輸出:不全是漢字
?>
<?php
$str = '漢字3測試';
if (preg_match('/([\x81-\xFE][\x40-\xFE])/', $str)) {
echo '含有漢字';
} else {
echo '不含有漢字';
}
// 輸出:含有漢字
$str2 = 'abc345';
if (preg_match('/([\x81-\xFE][\x40-\xFE])/', $str2)) {
echo '含有漢字';
} else {
echo '不含有漢字';
}
// 輸出:不含有漢字
?>
注意:GBK 正則基於字節特徵,**與源文件編碼無關**,只要輸入字符串實際為 GBK 編碼即可匹配。
**核心要求**:正則必須加 u 修飾符(PCRE_UTF8),否則按單字節解析導致錯誤。
<?php
$str = "php編程";
// \x{4e00}-\x{9fa5} 覆蓋常用漢字 20902 個
if (preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', $str)) {
echo "該字符串全部是中文";
} else {
echo "該字符串不全部是中文";
}
// 輸出:該字符串不全部是中文(含 php)
?>
<?php
$str = "PHP中文正則表達式教程2024";
preg_match_all('/[\x{4e00}-\x{9fa5}]+/u', $str, $matches);
print_r($matches[0]);
/*
Array
(
[0] => 中文正則表達式教程
)
*/
?>
<?php
$str = "用戶名:張三_123";
// 保留中文、數字、下劃線,其余替換為空
$clean = preg_replace('/[^\x{4e00}-\x{9fa5}0-9_]/u', '', $str);
echo $clean; // 輸出:張三_123
?>
U+4E00-U+9FA5 僅覆蓋基本漢字。若需支持生僻字、擴展區、日韓漢字,可擴展範圍:
<?php
// 擴展範圍(根據業務按需組合)
$patterns = [
'基本漢字' => '\x{4e00}-\x{9fa5}',
'擴展A區' => '\x{3400}-\x{4dbf}',
'擴展B區' => '\x{20000}-\x{2a6df}',
'擴展C區' => '\x{2a700}-\x{2b73f}',
'擴展D區' => '\x{2b740}-\x{2b81f}',
'擴展E區' => '\x{2b820}-\x{2ceaf}',
'兼容補充區' => '\x{f900}-\x{faff}',
'CJK 部首補充' => '\x{2e80}-\x{2eff}',
'康熙部首' => '\x{2f00}-\x{2fdf}',
];
// 組合正則(示例:基本+擴展A+兼容)
$han_regex = '/[' . implode('', array_slice($patterns, 0, 3)) . ']+/u';
?>
<?php
// 1. 檢測編碼
$encoding = mb_detect_encoding($str, ['UTF-8', 'GBK', 'GB2312', 'ASCII'], true);
// 2. 統一轉為 UTF-8 再處理(推薦)
if ($encoding !== 'UTF-8') {
$str = mb_convert_encoding($str, 'UTF-8', $encoding);
}
// 3. 使用 UTF-8 正則統一處理
if (preg_match('/^[\x{4e00}-\x{9fa5}]+$/u', $str)) {
// ...
}
?>
u 修飾符:UTF-8 正則必須加 /u,否則按字節匹配產生亂碼結果。\x{4e00} 避免編碼困擾。**UTF-8 統一用 /[\x{4e00}-\x{9fa5}]/u,GBK 用 /[\x81-\xFE][\x40-\xFE]/**。生產環境強烈建議**統一轉 UTF-8 後再用 UTF-8 正則**,消除編碼不一致帶來的所有隱患。掌握 Unicode 碼點範圍與 u 修飾符,是處理中文正則的核心鑰匙。