正则表达式教程
🚀 没写过正则?先花 10 分钟用一个真实任务(校验手机号)走完「认符号 → 写出来 → 跑通」, 只需要认识四个东西。后面十五篇解释「为什么」。写给会写代码、但正则永远靠复制粘贴的人。 第一篇用十分钟带你写出第一条能用的正则;从第二篇开始才讲「为什么」—— 引擎怎么工作、那些符号各自在解决什么问题。 不堆语法表:后面所有「它为什么匹配到了一大坨东西」, 都回到同一个模型上。
每篇末尾有练习:给一个真实需求,你来写正则。 答案默认折叠 —— 先自己写一遍,读懂和写得出是两件事。
章节顺序就是阅读顺序,从头读最省事。 示例语言统一用 JavaScript,方言差异(Python、grep) 单独放在最后一篇里讲 —— 大部分「抄来的正则不工作」都出在那 10% 上。
速查:已验证的示例
下面每一条都由 npm run test:regex 在每次构建前实跑, 结果是现算的。点「出处」看它在讲什么。
| 模式 | 输入 | 结果 | 出处 |
|---|---|---|---|
/13800138000/ | "13900139000" | false | 10 分钟写出你的第一条正则 |
/^1\d{10}$/ | "13900139000" | true | 10 分钟写出你的第一条正则 |
/^1\d{10}$/ | "13800138000abc" | false | 10 分钟写出你的第一条正则 |
/b/ | "ab" | true | 正则引擎在干什么 |
/.*b/ | "aabab" | ["aabab"] | 正则引擎在干什么 |
/(a|ab)/ | "ab" | ["a","a"] | 正则引擎在干什么 |
/(a|ab)c/ | "abc" | ["abc","ab"] | 正则引擎在干什么 |
/^.$/ | "\n" | false | 字符与字符类 |
/^[.+]$/ | "ab" | false | 字符与字符类 |
/^[^a]$/ | "\n" | true | 字符与字符类 |
/[a-c]/g | "abcd-" | ["a","b","c"] | 字符与字符类 |
/^\s$/ | " " | true | 字符与字符类 |
/^colou?r$/ | "color" | true | 量词与贪婪/懒惰 |
/^ab*$/ | "a" | true | 量词与贪婪/懒惰 |
/<.+>/ | "<b>粗体</b>" | ["<b>粗体</b>"] | 量词与贪婪/懒惰 |
/<.+?>/ | "<b>粗体</b>" | ["<b>"] | 量词与贪婪/懒惰 |
/<.+?>/g | "<b>粗体</b>" | ["<b>","</b>"] | 量词与贪婪/懒惰 |
/^\d{3,4}$/ | "12345" | false | 量词与贪婪/懒惰 |
/\s+/g | " a b " | " a b " | 量词与贪婪/懒惰 |
/^cat/ | "concat" | false | 位置:锚点与零宽 |
/^/gm | "a\nb" | "> a\n> b" | 位置:锚点与零宽 |
/^\w+/gm | "alpha\nbeta\ngamma" | ["alpha","beta","gamma"] | 位置:锚点与零宽 |
/a$/ | "a\n" | null | 位置:锚点与零宽 |
/\bcat\b/g | "cat category concat cat." | ["cat","cat"] | 位置:锚点与零宽 |
/\b中文\b/ | "中文" | false | 位置:锚点与零宽 |
/\bhello\b/ | "说hello吧" | true | 位置:锚点与零宽 |
/^(ab)+$/ | "abab" | true | 分组、捕获与反向引用 |
/(\d{4})-(\d{2})-(\d{2})/ | "2026-09-11" | ["2026-09-11","2026","09","11"] | 分组、捕获与反向引用 |
/(?<y>\d{4})-(?<m>\d{2})-(?<d>\d{2})/ | "2026-09-11" | "11/09/2026" | 分组、捕获与反向引用 |
/^(\w)\1$/ | "aa" | true | 分组、捕获与反向引用 |
/(\w+) \1/ | "the the cat" | ["the the","the"] | 分组、捕获与反向引用 |
/^(a)?(b)$/ | "b" | ["b",null,"b"] | 分组、捕获与反向引用 |
/"(.+?)"/ | "说 \"hello\" 和 \"world\"" | ["\"hello\"","hello"] | 分组、捕获与反向引用 |
/^cat|dog$/ | "cat food" | true | 选择分支与优先级 |
/cat|category/ | "category" | ["cat"] | 选择分支与优先级 |
/^(cat|dog)$/ | "dog" | ["dog","dog"] | 选择分支与优先级 |
/\b(cat|dog)s\b/g | "cats dogs cows" | ["cats","dogs"] | 选择分支与优先级 |
/\b(cat|dog)\b/g | "cat category dog" | "pet category pet" | 选择分支与优先级 |
/\d+(?=元)/ | "价格 100元" | ["100"] | 先行与后行 |
/\b\d+\b(?!元)/g | "100元 200米 300" | ["200","300"] | 先行与后行 |
/(?<=¥)\d+/g | "¥100 和 $200" | ["100"] | 先行与后行 |
/^(?=.*\d)(?=.*[a-z]).{8,}$/ | "abc12345" | true | 先行与后行 |
/\B(?=(\d{3})+$)/g | "123456" | "123,456" | 先行与后行 |
/(?<![一-龥])北京(?![一-龥])/ | "去北京玩" | false | 先行与后行 |
/(?<![一-龥])北京(?![一-龥])/ | "去 北京 玩" | true | 先行与后行 |
/\d+/g | "a1b" | [true,false] | 修饰符 |
/(\w+) \1/i | "The the cat" | ["The the","The"] | 修饰符 |
/<p>.+</p>/s | "<p>a\nb</p>" | ["<p>a\nb</p>"] | 修饰符 |
/./gu | "😀a" | ["😀","a"] | 修饰符 |
/\p{Script=Han}+/gu | "去北京玩 abc" | ["去北京玩"] | 修饰符 |
/\d+/y | "a1" | false | 修饰符 |
/^[^\s@]+@[^\s@]+\.[^\s@]+$/ | "a@b" | false | 实战:校验、提取、替换 |
/^\d{4}-\d{2}-\d{2}$/ | "2026-13-45" | true | 实战:校验、提取、替换 |
/^(\w+)\s+\[([^\]]+)\]\s+(.+)$/ | "ERROR [db] [retry] failed" | ["ERROR [db] [retry] failed","ERROR","db","[retry] failed"] | 实战:校验、提取、替换 |
/\d+/g | "a1b22" | "a**1**b**22**" | 实战:校验、提取、替换 |
/(\d{3})\d{4}(\d{4})/ | "13812345678" | "138****5678" | 实战:校验、提取、替换 |
/d+/ | "123" | false | 正则不工作怎么查 |
/^a b$/ | "a b" | false | 正则不工作怎么查 |
/^(\w+)@/ | "a.b@example.com" | null | 正则不工作怎么查 |
/^abc$/ | "abc" | false | 正则不工作怎么查 |
/^\d{4}$-^\d{2}$/ | "2026-09" | false | 让同事读懂,也让机器测得了 |
/^[a-z]+$/i | "ABC" | true | 让同事读懂,也让机器测得了 |
/^\d{4} - \d{2}$/ | "2026-09" | false | 让同事读懂,也让机器测得了 |
/\[(.+)\]\((.+)\)/ | "[a](x) 和 [b](y)" | ["[a](x) 和 [b](y)","a](x) 和 [b","y"] | 一个需求走完全程 |
/\[([^\]]+)\]\(([^)]+)\)/g | " [link](b)" | ["[img](a.png)","[link](b)"] | 一个需求走完全程 |
/(?<!!)\[([^\]]+)\]\(([^)]+)\)/ | "" | null | 一个需求走完全程 |
/(?<!!)\[([^\]]+)\]\(([^)]+)\)/g | "`[not](a link)` [real](b)" | ["[not](a link)","[real](b)"] | 一个需求走完全程 |
/^-?\d+$/ | "-42" | true | 常用模式速查 |
/^[1-9]\d*$/ | "007" | false | 常用模式速查 |
/^-?\d+(?:\.\d+)?$/ | "42" | true | 常用模式速查 |
/^1[3-9]\d{9}$/ | "12800138000" | false | 常用模式速查 |
/^(?:(?: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)$/ | "256.1.1.1" | false | 常用模式速查 |
/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i | "#ffff" | false | 常用模式速查 |
/^\s+|\s+$/g | " a b " | "a b" | 常用模式速查 |
/[一-龥]+/g | "去北京玩 abc" | ["去北京玩"] | 常用模式速查 |
/\([^)]*\)/ | "(a(b)c)" | ["(a(b)"] | 什么时候不该用正则 |
/\(.*\)/ | "(a) (b)" | ["(a) (b)"] | 什么时候不该用正则 |
/<[^>]+>/ | "<a title=\"a>b\">x</a>" | ["<a title=\"a>"] | 什么时候不该用正则 |
/[^,]+/g | "a,\"b,c\",d" | ["a","\"b","c\"","d"] | 什么时候不该用正则 |