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

PHP 正則表達式匹配中文:preg_match、mb_ereg 與 Unicode 屬性完整指南

     編輯:PHP 相關知識

中文匹配的編碼與正則基礎

PHP 正則處理中文需考慮編碼(UTF-8/GBK/BIG5)、PCRE 版本、多位元組字元邊界。本文系統整理各編碼下的匹配模式、常見陷阱與現代最佳實踐(Unicode 屬性)。

編碼無關的現代寫法:Unicode 屬性(推薦,PHP 5.1+ / PCRE 8.10+)

使用 \p{Han} 匹配所有漢字(CJK Unified Ideographs),\p{Han}+ 匹配連續漢字串。必須加 u 修飾符 啟用 UTF-8 模式。

$str = 'Hello 世界 123 测试';

// 1. 判斷是否包含中文
if (preg_match('/\p{Han}/u', $str)) {
    echo '包含中文';
}

// 2. 判斷純中文字串(全字串皆為漢字)
if (preg_match('/^\p{Han}+$/u', $str)) {
    echo '純中文';
} else {
    echo '含非中文';
}

// 3. 提取所有中文詞彙
preg_match_all('/\p{Han}+/u', $str, $matches);
print_r($matches[0]); // ['世界', '测试']

// 4. 替換中文為標記
echo preg_replace('/\p{Han}+/u', '[中文]', $str); // Hello [中文] 123 [中文]

擴展:常用 Unicode 區塊屬性

屬性涵蓋範圍說明
\p{Han}CJK Unified Ideographs通用漢字(簡繁體、日韓漢字)
\p{Hiragana}平假名日文平假名
\p{Katakana}片假名日文片假名
\p{Hangul}韓文音節韓文
\p{L}所有字母含拉丁、希臘、西里爾、漢字等
\p{N}所有數字含阿拉伯數字、中文數字、羅馬數字
\p{P}所有標點含中文標點、英文標點

傳統編碼特定模式(GBK/GB2312/BIG5)

若專案仍使用 GBK/GB2312 編碼,無法使用 u 修飾符,需用位元組範圍匹配:

// GBK/GB2312:雙位元組,高位 0x81-0xFE,低位 0x40-0xFE (排除 0x7F)
$gbk_han = '/[\x81-\xFE][\x40-\xFE]/';

// BIG5:高位 0x81-0xFE,低位 0x40-0x7E 及 0xA1-0xFE
$big5_han = '/[\x81-\xFE][\x40-\x7E\xA1-\xFE]/';

// 判斷純中文(GBK 範例)
$str_gbk = '中文測試'; // 假設檔案儲存為 GBK
if (preg_match('/^(' . $gbk_han . ')+$/', $str_gbk)) {
    echo 'GBK 純中文';
}

// 注意:若 PHP 檔案為 UTF-8 但字串為 GBK,需先 iconv 轉碼再用 \p{Han}

mb_ereg 系列函數(不需 u 修飾符,使用內部編碼)

// 設定內部編碼(腳本頂端呼叫一次)
mb_regex_encoding('UTF-8'); // 或 'GBK', 'BIG5'

$str = '中文測試123';

// mb_eregi:不分大小寫匹配(中文無大小寫,等同 mb_ereg)
if (mb_ereg('\p{Han}', $str)) { // PHP 5.4+ mb_ereg 支援 Unicode 屬性
    echo '含中文';
}

// 純中文判斷
if (mb_ereg('^\p{Han}+$', $str)) {
    echo '純中文';
}

// 分割中英文
$parts = mb_split('(\p{Han}+)', $str); // 保留分隔符需用 mb_ereg 迴圈

常見實務場景與模式

需求模式(UTF-8)說明
用戶名:中英數底線,2-20 字/^[\p{Han}\w]{2,20}$/u\w = [a-zA-Z0-9_]
密碼:含至少一個中文/^(?=.*\p{Han}).{8,}$/u正向預查
過濾 Emoji(輔助平面)/[\x{10000}-\x{10FFFF}]/u或 /[\p{So}\p{Cn}]/u
提取中文句子(含中文標點)/[\p{Han}\p{P}]+/u\p{P} 含所有標點
驗證身分證字號(台)/^[A-Z][12]\d{8}$/無中文,僅示例
驗證統一編號(台)/^\d{8}$/同上

效能與避坑指南

  • 一定要加 u 修飾符:否則 PCRE 將字串視為單位元組,導致多位元組字元被拆解匹配,產生錯誤結果。
  • 避免在大量資料用 preg_match_all 搭配複雜回溯模式:如 /(\p{Han}+)+/u 會導致災難性回溯,改用 /\p{Han}+/u 並程式端處理。
  • PCRE 回溯限制:ini_set('pcre.backtrack_limit', '1000000') 可提高上限,但優先優化模式。
  • 字串編碼不一致:確保 PHP 檔案編碼、資料庫連線編碼、HTTP 輸出編碼、正則模式編碼全部一致(建議全站 UTF-8)。
  • mbstring.func_overload:若開啟(已棄用),preg_* 可能受影響,建議關閉並顯式使用 mb_* 函數。

完整驗證類別範例

class ChineseValidator {
    public static function hasChinese(string $str): bool {
        return (bool)preg_match('/\p{Han}/u', $str);
    }

    public static function isPureChinese(string $str): bool {
        return (bool)preg_match('/^\p{Han}+$/u', $str);
    }

    public static function extractChinese(string $str): array {
        preg_match_all('/\p{Han}+/u', $str, $m);
        return $m[0];
    }

    public static function filterChinese(string $str, string $replacement = ''): string {
        return preg_replace('/\p{Han}+/u', $replacement, $str);
    }

    public static function usernameValid(string $username): bool {
        // 2-20 字,中英數底線,至少一個中文或英文
        return (bool)preg_match('/^(?=.*[\p{Han}a-zA-Z])[\p{Han}\w]{2,20}$/u', $username);
    }
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved