全角字符 (全形) 佔用兩字節,半角佔用一字節,常見於用戶輸入標準化、搜索關鍵詞預處理、數據清洗。本文提供四種 PHP 實現方案,從簡單正則到高性能查表,附 Unicode 碼位對照表。
$str = "0123ABCDFWS\",.?<>{}[]*&^%#@!~()+-|:;";
// 非 UTF-8 環境下:第二字節 - 0x80 得到半角
$str = preg_replace('/\xa3([\xa1-\xfe])/e', 'chr(ord("\\1")-0x80)', $str);
echo $str; // 0123ABCDFWS\".<>[]*&^%#@!~()+-|:;
// 注意:/e 修飾符 PHP 7.1+ 棄用,UTF-8 下無效
原理:GBK/Big5 編碼中,全角字符第二字節 = 半角字符碼位 + 0x80。UTF-8 編碼無此規律。
$map = [
'0'=>'0','1'=>'1','2'=>'2','3'=>'3','4'=>'4','5'=>'5','6'=>'6','7'=>'7','8'=>'8','9'=>'9',
'A'=>'A','B'=>'B','C'=>'C','D'=>'D','E'=>'E','F'=>'F','G'=>'G','H'=>'H','I'=>'I','J'=>'J',
'K'=>'K','L'=>'L','M'=>'M','N'=>'N','O'=>'O','P'=>'P','Q'=>'Q','R'=>'R','S'=>'S','T'=>'T',
'U'=>'U','V'=>'V','W'=>'W','X'=>'X','Y'=>'Y','Z'=>'Z',
'a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j',
'k'=>'k','l'=>'l','m'=>'m','n'=>'n','o'=>'o','p'=>'p','q'=>'q','r'=>'r','s'=>'s','t'=>'t',
'u'=>'u','v'=>'v','w'=>'w','x'=>'x','y'=>'y','z'=>'z',
];
$str = preg_replace_callback(
'/[\xEF][\xBC][\x90-\x99]|[\xEF][\xBD][\x81-\x9A\xA1-\xBA]/',
fn($m) => $map[$m[0]] ?? $m[0],
$str
);
原理:UTF-8 中全角數字 U+FF10~FF19 編碼為 EF BC 90~99,大寫字母 U+FF21~FF3A 為 EF BD 81~9A,小寫 U+FF41~FF5A 為 EF BD A1~BA。
function convertStrType(string $str, string $type): string {
$full = ['0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'-',' ',':','.',',','/','%','#','!','@','&','(',')','<','>','"',''','?','[',']','{','}','\','|','+','=','_','^','¥',' ̄','`'];
$half = ['0','1','2','3','4','5','6','7','8','9',
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
'-',' ',':','.',',','/','%','#','!','@','&','(',')','<','>','"',"'",'?','[',']','{','}','\\','|','+','=','_','^','¥','~','`'];
return ($type === 'TO_DBC') // 全角轉半角
? str_replace($full, $half, $str)
: str_replace($half, $full, $str); // 半角轉全角
}
function makeSemiangle(string $str): string {
$map = [
'0'=>'0','1'=>'1','2'=>'2','3'=>'3','4'=>'4','5'=>'5','6'=>'6','7'=>'7','8'=>'8','9'=>'9',
'A'=>'A','B'=>'B','C'=>'C','D'=>'D','E'=>'E','F'=>'F','G'=>'G','H'=>'H','I'=>'I','J'=>'J',
'K'=>'K','L'=>'L','M'=>'M','N'=>'N','O'=>'O','P'=>'P','Q'=>'Q','R'=>'R','S'=>'S','T'=>'T',
'U'=>'U','V'=>'V','W'=>'W','X'=>'X','Y'=>'Y','Z'=>'Z',
'a'=>'a','b'=>'b','c'=>'c','d'=>'d','e'=>'e','f'=>'f','g'=>'g','h'=>'h','i'=>'i','j'=>'j',
'k'=>'k','l'=>'l','m'=>'m','n'=>'n','o'=>'o','p'=>'p','q'=>'q','r'=>'r','s'=>'s','t'=>'t',
'u'=>'u','v'=>'v','w'=>'w','x'=>'x','y'=>'y','z'=>'z',
// 標點符號 (常用)
'('=>'(', ')'=>')', '〔'=>'[', '〕'=>']', '【'=>'[', '】'=>']', '〖'=>'[', '〗'=>']',
'“'=>'"', '”'=>'"', '‘'=>"'", '’'=>"'", '《'=>'<', '》'=>'>',
'%'=>'%', '+'=>'+', '—'=>'-', '-'=>'-', '~'=>'~', ':'=>':', '。'=>'.', '、'=>',', ','=>',', ';'=>';',
'?'=>'?', '!'=>'!', '…'=>'...', '‖'=>'|', '|'=>'|', '〃'=>'"', ' '=>' '
];
return strtr($str, $map);
}
| 方案 | 耗時 | 優點 | 缺點 |
|---|---|---|---|
| 正則 /e | ~2.1s | 代碼極短 | 非 UTF-8、/e 棄用、安全風險 |
| preg_replace_callback | ~1.8s | UTF-8 兼容、可擴展 | 回調開銷大 |
| str_replace 陣列 | ~0.9s | 簡單、雙向 | 多次遍歷字符串 |
| strtr | ~0.3s | 單次遍歷、C 級性能、內存友好 | 需構建完整映射表 |
| 字符類型 | 半角碼位 | 全角碼位 | 差值 |
|---|---|---|---|
| 數字 0-9 | U+0030~U+0039 | U+FF10~U+FF19 | +0xFEE0 |
| 大寫 A-Z | U+0041~U+005A | U+FF21~U+FF3A | +0xFEE0 |
| 小寫 a-z | U+0061~U+007A | U+FF41~U+FF5A | +0xFEE0 |
| 空格 | U+0020 | U+3000 (全形空格) | 特殊 |
| 常用標點 | U+0021~U+007E | U+FF01~U+FF5E | +0xFEE0 (大部分) |
makeSemiangle() 標準化
3. 搜索引擎索引前同步轉換,保證全半角混合查詢命中
4. 正則匹配時使用 /u 修飾符正確處理 Unicode
5. 數據庫列設置 utf8mb4_general_ci 排序規則,原生支持全半角不敏感比較
掌握 Unicode 編碼規律,選擇 strtr 方案,即可高效解決全半角混雜帶來的業務 Bug。