正則表達式的基石是字符匹配。理解普通字符、特殊元字符、非打印字符轉義、方括號字符類別的語法與行為,是編寫精準模式的前提。本文系統梳理字符級匹配規則,並給出常用字符類別速查表。
字符分類層級
| 層級 | 包含 | 示例 |
| 普通字符 | 字母、數字、標點、符號 (非元字符) | a 7 M @ # |
| 元字符 | 有特殊含義,需轉義匹配字面值 | . * + ? ^ $ [ ] { } ( ) | \ / |
| 轉義序列 | 反斜杠 + 字符,表示特殊字符 | \n \t \r \f \v \cM |
| 字符類別 | 方括號內的字符集合 | [abc] [a-z] [^0-9] |
元字符轉義規則
匹配字面元字符需前加反斜杠:
/\./ # 匹配字面點號 .
/\*/ # 匹配字面星號 *
/\?/ # 匹配字面問號 ?
/\// # 匹配字面斜杠 / (在 /.../ 定界符中)
/\\/ # 匹配字面反斜杠 \
/\(/ # 匹配字面左括號 (
/\[/ # 匹配字面左方括號 [
/\|/ # 匹配字面縱向符 |
/\^/ # 匹配字面脫字符 ^
/\$/ # 匹配字面美元符 $
/\{/ # 匹配字面左大括號 {
非打印字符轉義表
| 轉義 | 含義 | ASCII | 等價 |
\n | 換行 (LF) | 10 (0x0A) | \x0a \cJ |
\r | 回車 (CR) | 13 (0x0D) | \x0d \cM |
\t | 水平製表 (Tab) | 9 (0x09) | \x09 \cI |
\f | 換頁 (FF) | 12 (0x0C) | \x0c \cL |
\v | 垂直製表 (VT) | 11 (0x0B) | \x0b \cK |
\s | 任意空白字符 | - | [\f\n\r\t\v] |
\S | 任意非空白字符 | - | [^\f\n\r\t\v] |
\cX | 控制字符 (X=A-Z) | - | 如 \cM=CR |
\xHH | 十六進制字符 (2位) | - | \x41 = 'A' |
\uHHHH | Unicode 字符 (4位) | - | \u4E2D = '中' |
點號 `.` 匹配規則
- 默認匹配除換行符外的任意單字符
- 加
s 修飾符 (PCRE_DOTALL) 後匹配包含換行的任意字符
- 在字符類別 `
[.]` 中為字面點號,無需轉義
<?php
$text = "a1c\na-c\na#c";
preg_match_all('/a.c/', $text, $m); // 不匹配換行
// 結果: a1c, a-c, a#c (若無換行) 或僅第一行
preg_match_all('/a.c/s', $text, $m); // s 修飾符,匹配含換行
// 結果: a1c, a-c, a#c (跨行)
字符類別 `[]` 完整語法
基本形式
[abc] # 匹配 a 或 b 或 c (單字符)
[a-z] # 匹配 a 到 z 任意小寫字母
[A-Za-z0-9] # 字母數字
[^abc] # 否定類:匹配非 a/b/c 的任意字符
[^a-z] # 非小寫字母
特殊字符在類別內的行為
| 字符 | 類別內含義 | 注意 |
] | 結束類別 | 放首位 `[]abc]` 表示字面 ] |
\ | 轉義符 | \\ 匹配 \ |
- | 範圍連字符 | 首位 `[-abc]` 或末位 `[abc-]` 表示字面 - |
^ | 否定 (僅首位) | 非首位表示字面 ^ |
& : = 等 | 字面字符 | 無特殊含義 |
預定義字符類別簡寫
| 簡寫 | 等價類別 | 說明 |
\d | [0-9] | 數字 |
\D | [^0-9] | 非數字 |
\w | [A-Za-z0-9_] | 單詞字符 (含下劃線) |
\W | [^A-Za-z0-9_] | 非單詞字符 |
\s | [\f\n\r\t\v] | 空白字符 |
\S | [^\f\n\r\t\v] | 非空白字符 |
\p{L} | - | Unicode 字母 (需 u 修飾符) |
\p{Han} | - | 漢字 (需 u 修飾符) |
\X | - | 擴展書寫字符組 (需 u 修飾符) |
實戰:常用驗證模式
<?php
$patterns = [
'email' => '/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$/',
'url' => '/^https?:\/\/[^\s\/$.?#].[^\s]*$/i',
'ipv4' => '/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$/',
'mobile_cn' => '/^1[3-9]\d{9}$/',
'id_card' => '/^[1-9]\d{5}(?:19|20)\d{2}(?:0[1-9]|1[0-2])(?:0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/',
'chinese' => '/^[\x{4e00}-\x{9fa5}]+$/u', // Unicode 漢字範圍
'username' => '/^[A-Za-z0-9_]{3,16}$/',
'password' => '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/',
];
function validate($pattern, $input) {
return (bool)preg_match($pattern, $input);
}
// 測試
var_dump(validate($patterns['email'], 'test@example.com')); // true
var_dump(validate($patterns['mobile_cn'], '13800138000')); // true
var_dump(validate($patterns['chinese'], '中文測試')); // true (需 PHP 7.1+)
var_dump(validate($patterns['password'], 'Abc12345@')); // true
Unicode 屬性匹配 (PCRE + u 修飾符)
<?php
// 僅匹配漢字
$han = '/^\p{Han}+$/u';
var_dump(preg_match($han, '中文')); // 1
var_dump(preg_match($han, 'English')); // 0
// 匹配所有字母 (含多語言)
$letter = '/^\p{L}+$/u';
var_dump(preg_match($letter, '中文')); // 1 (漢字屬 Lo)
var_dump(preg_match($letter, 'English')); // 1
var_dump(preg_match($letter, '123')); // 0
總結
字符匹配是正則的原子操作。牢記:元字符需轉義,點號不匹配換行除非加 s,字符類別內規則不同,善用預定義簡寫 \d \w \s,Unicode 場景必加 u 修飾符並用 \p{} 屬性。