表單校驗
手機號、郵編、日期格式、密碼強度——課程第 22–24 關的三個模式可以直接用到前端表單裏;記住加錨點,並把「2 月 30 日」這類語義檢查留給代碼。
使用指南
正則表達式課是一門 25 關的交互式教程:每一關給你一段測試文本和一個目標(「匹配這幾個、不要匹配那幾個」或「捕獲出某一部分」),你在輸入框裏改表達式,右側實時高亮所有匹配和分組,判定器逐項告訴你哪些目標已經達成。全部判定用瀏覽器自帶的 JavaScript 正則引擎完成,不上傳任何文本。
更新於 2026-09-094 个来源约 13 分钟读完
正則表達式課是一門 25 關的交互式教程:每一關給你一段測試文本和一個目標(「匹配這幾個、不要匹配那幾個」或「捕獲出某一部分」),你在輸入框裏改表達式,右側實時高亮所有匹配和分組,判定器逐項告訴你哪些目標已經達成。全部判定用瀏覽器自帶的 JavaScript 正則引擎完成,不上傳任何文本。
課程按難度遞進:先是字面量、點號、轉義這些「找字符」的基礎;然後是字符類與範圍、預定義類 \d \w \s、四種量詞;接着是錨點與單詞邊界、選擇符、三種分組與反向引用、貪婪與懶惰;再進入先行/後行斷言與標誌;最後用三個真實模式(中國大陸手機號、郵箱、日期)綜合練習,並以一關「災難性回溯」收尾,讓你親手寫出一條會讓引擎卡住的表達式,再修好它。
學完大約需要 60 分鐘。適合從來沒寫過正則、或者「會抄不會改」的人;已經熟悉正則的讀者可以直接跳到第 17 關之後的環視與陷阱部分。
?lesson=n 的鏈接,打開後直接落在那一關。「重置進度」清空本課程全部記錄。本頁上方就是課程本體:左側目錄選關,中間輸入正則,判定實時出現。
第 14 關「捕獲組」的目標是從 2026-09-09 裏取出年份。下面是一次通關過程的記錄:
測試文本 發佈日期:2026-09-09,截止:2027-01-31
第一次嘗試 \d+
匹配 2026 09 09 2027 01 31 ← 6 處匹配,沒有捕獲組
判定 ✕ 只應匹配兩個完整日期 ✕ 組 1 應為年份
第二次嘗試 (\d{4})-\d{2}-\d{2}
匹配 2026-09-09 2027-01-31 ← 2 處匹配
組 1 2026 2027
判定 ✓ 匹配數 2 ✓ 組 1 = 2026 / 2027 → 通關
第 25 關「災難性回溯」則反過來:先讓你寫出 ^(a+)+$ 這類嵌套量詞模式,對一串 aaaaaaaaaaaaaaaaaaaaaaaaaaaa! 測試,頁面會報告嘗試次數呈指數增長;再要求改成 ^a+$ 這樣的等價寫法通關。
正則表達式(regular expression)用一小套符號描述「一類字符串長什麼樣」。字母數字大多代表自己,十幾個元字符(. * + ? ^ $ | ( ) [ ] { } \)則有特殊含義。引擎拿着模式從左到右掃描文本,在每個位置嘗試匹配,找到就報告位置與長度。這門課用的是 JavaScript(ECMAScript)方言,它與 Python、Java、Go 的正則在基礎語法上幾乎一致,差別集中在環視、Unicode 屬性與部分標誌上。
cat 就匹配連續的 c、a、t 三個字符。點號 . 匹配除換行外的任意一個字符,所以 c.t 能匹配 cat、cut、c9t。當你真的想找一個句點(比如文件擴展名前的點)時,要寫 \.——反斜槓讓元字符回到字面意義。所有元字符都可以這樣轉義;在字符類裏只有 ] \ ^ - 需要轉義。
方括號列出候選字符:[aeiou] 匹配任一元音;[a-z]、[0-9] 用連字符表示範圍,可以並列寫成 [A-Za-z0-9_];開頭加 ^ 取反,[^0-9] 匹配任何非數字。三個常用的預定義類是它們的縮寫:
| 類 | 等價於 | 説明 |
|---|---|---|
\d |
[0-9] |
數字(不含中文數字與全角數字) |
\w |
[A-Za-z0-9_] |
「單詞字符」,注意漢字不算 |
\s |
[ \t\n\r\f\v…] |
空白,含全角空格 |
大寫版本 \D \W \S 是各自的取反。\w 不含漢字是中文用户最常踩的坑:匹配中文要寫 [\u4e00-\u9fa5],或在 u 標誌下用 \p{Script=Han}。
量詞跟在一個原子(單個字符、字符類或分組)後面,規定它重複幾次:
* 零次或多次,+ 一次或多次,? 零次或一次;{n} 恰好 n 次,{n,} 至少 n 次,{n,m} n 到 m 次。\d{4} 比 \d\d\d\d 更好讀,\d{11} 是手機號位數。量詞只作用於緊挨着它的那一個原子:ab+ 是 a 後面跟一個或多個 b,要重複整個 ab 得寫 (ab)+。
^ 和 $ 不匹配字符,只匹配位置:字符串開頭和結尾(多行模式下是每一行的開頭結尾)。表單校驗幾乎總要寫 ^…$,否則 \d{11} 會「匹配」到 12 位號碼的前 11 位。\b 是單詞邊界——\w 與 \W(或串首尾)之間的位置。\bcat\b 能匹配 a cat 而不匹配 concatenate。同樣因為 \w 不含漢字,\b 在中文裏基本無用。
| 表示「或」,優先級最低:cat|dog 匹配兩個詞之一;要限定範圍要用括號,gr(a|e)y。括號同時創建捕獲組:匹配成功後可以按編號取出組內文本(match[1]),或在替換字符串裏用 $1 引用——這是正則最有生產力的用法之一,比如把 2026-09-09 換成 09/09/2026 只需一次 replace。
(?<year>\d{4}) 是命名組,用 groups.year 讀取,比數字編號更不容易在改模式時錯位。(?:…) 是非捕獲組:只分組、不佔編號,適合只是想給量詞或選擇劃範圍的場合。\1 是反向引用——要求這裏再出現一次第 1 組捕獲到的內容:(\w)\1 匹配 ll、oo 這樣的雙寫字母,<(\w+)>.*?</\1> 匹配成對的 HTML 標籤。
量詞默認是貪婪的:儘量多吃,吃多了再吐。對 "a" and "b" 用 ".+" 會一口氣匹配從第一個引號到最後一個引號的全部內容。在量詞後加 ? 變成懶惰:".+?" 儘量少吃,得到 "a" 和 "b" 兩個匹配。另一種更精確的寫法是用否定字符類 "[^"]+",它不依賴回溯,通常也更快。
環視(lookaround)像錨點一樣只匹配位置,但條件是「旁邊有沒有某個模式」:
(?=…) 先行:後面必須跟着 …;\d+(?=元) 匹配 100元 裏的 100,但不把「元」算進匹配。(?!…) 否定先行:後面不能是 …。(?<=…) 後行:前面必須是 …;(?<=¥)\d+ 匹配價格數字而不含貨幣符號。(?<!…) 否定後行。JavaScript 自 ES2018 起支持後行斷言,Safari 16.4 之後才全面可用;Python 的後行斷言要求定長。密碼強度校驗是環視的典型用法:^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$ 用三個先行斷言從同一位置分別檢查「含數字、含小寫、含大寫」,然後 .{8,} 消耗整個串。
標誌寫在模式外面:i 忽略大小寫;g 找出所有匹配而不是第一個(課程裏的高亮始終用 g);m 讓 ^ $ 匹配每一行;s 讓 . 也能匹配換行;u 開啓 Unicode 模式,. 按碼位而不是 UTF-16 碼元匹配,emoji 才算一個字符;y 粘連匹配,從 lastIndex 處必須立刻匹配。
中國大陸手機號:^1[3-9]\d{9}$——1 開頭、第二位 3–9、共 11 位。不要試圖枚舉運營商號段,號段每年都在增加。
郵箱:完全符合 RFC 5322 的正則長達數千字符且並不實用。表單裏的合理寫法是 ^[^\s@]+@[^\s@]+\.[^\s@]+$:有且只有一個 @、兩側非空、域名部分至少一個點。真正的驗證靠發一封確認郵件。
日期:^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ 能限定月份 01–12、日 01–31,但不能知道 2 月有幾天——語法校驗交給正則,語義校驗交給代碼。
JavaScript、Python、Java、PCRE 的正則引擎都是回溯式(backtracking):碰到多種可能的分法就先試一種,失敗再退回來試下一種。嵌套量詞讓分法數量呈指數增長:^(a+)+$ 面對 30 個 a 加一個 !,引擎要試超過 2^30 種切分方式才能宣告失敗,瀏覽器標籤頁會卡死幾秒到幾分鐘。這類模式若接受用户輸入,就是一種拒絕服務攻擊(ReDoS)。
避免的原則:不讓兩個相鄰的量詞能匹配同樣的字符((a+)+、(\w+\s?)+、(.*)* 都是危險信號);用否定字符類取代懶惰的 .*?;給輸入設長度上限。Go 與 Rust 的正則庫採用 Thompson NFA / DFA 實現,保證線性時間,但代價是不支持反向引用與環視——Russ Cox 的文章把兩種實現的差異講得最清楚。
匹配嵌套結構(括號配對、HTML 全文)、需要「計數」的任務(判斷左右括號數相等)、依賴上下文語義的判斷(這個數字是不是合法日期),正則都做不到或做得很難。它是詞法層的工具:找出 token、切分、簡單校驗、批量替換——在這些事上它無可替代。
(?i) 內聯修飾符、Python 的 (?P<name>)、Java 的 \p{javaLowerCase} 等方言差異,也不講 POSIX 字符類 [[:alpha:]]。u;\p{…} 屬性轉義、v 標誌的集合運算不在課程範圍。\w 能匹配漢字」:不能。\w 只有 ASCII 字母、數字和下劃線,匹配中文用 [\u4e00-\u9fa5] 或 \p{Script=Han}(需 u 標誌)。. 匹配任何字符」:默認不匹配換行;要跨行匹配加 s 標誌或用 [\s\S]。\d{11} 就只接受 11 位」:沒有錨點時它會在更長的數字串裏找到一段 11 位;校驗一定要 ^…$。[A-z] 是所有字母」:ASCII 裏大寫 Z(90)和小寫 a(97)之間還有 [ \ ] ^ _ \`` 六个符号,会被一并匹配;要写 [A-Za-z]`。ab+ 只重複 b;ab{2} 匹配 abb,不匹配 abab。>、註釋都會讓正則失效,請用 DOM 解析器。手機號、郵編、日期格式、密碼強度——課程第 22–24 關的三個模式可以直接用到前端表單裏;記住加錨點,並把「2 月 30 日」這類語義檢查留給代碼。
VS Code、Sublime、JetBrains 系列的查找替換都支持正則與 $1 引用。學完分組一節,你可以一次把 2026-09-09 全部改成 09/09/2026,或給所有 console.log( 加上前綴。
從幾萬行日誌裏抓出 IP、狀態碼、耗時:(\d+\.\d+\.\d+\.\d+).*?" (\d{3}) (\d+)ms 之類的模式配合命名組,幾行腳本就能出統計。
看到 (\w+\s?)+$、(.*a)+、(a|aa)+ 這類嵌套或重疊量詞出現在處理用户輸入的位置,就該要求改寫或加長度限制。
判定看的是結果不是寫法:只要應匹配的全部命中、不應匹配的全部落空、捕獲組內容一致,就算通關。參考答案只是其中一種寫法。
通常是「不應匹配」的片段也被匹配了,或者匹配範圍比目標多了一個字符(比如把標點吃進去了)。看結果條裏哪一項是 ✕。
第 1–18 關的語法在主流語言裏完全通用。環視一關的後行斷言在 Python 裏要求定長,命名組寫法 Python 是 (?P<name>…);標誌的寫法各語言不同。
存在當前瀏覽器的 localStorage 裏,不上傳。換瀏覽器或清除站點數據會丟;可以用「分享本關」的鏈接記下學到哪一關。
演示用的是模擬步數計數,超過閾值就判為「災難性回溯」。真的執行會讓整個標籤頁無響應,無法給你反饋。
課程完全在瀏覽器本地運行:你輸入的表達式與測試文本只交給瀏覽器自帶的正則引擎,不發送到任何服務器;通關進度保存在本機 localStorage。關閉頁面後輸入內容即被釋放。
更新於 2026-09-09
25 關交互式正則教程:字面量、字符類、量詞、分組、環視到回溯陷阱,改表達式即時看匹配
此工具尚未完整翻譯,部分內容使用源文或回退語言。
目標写一个表达式,匹配所有含有 cat 的词,不匹配其它词。
最简单的正则就是一串普通字符:cat 会在文本里寻找连续的 c、a、t。正则默认是「包含」而不是「等于」——concat 和 category 里都有 cat,所以也算匹配。字母、数字、空格、中文都是字面量,只有十几个符号有特殊含义,后面几关逐个介绍。