一、正则表达式是什么
正则表达式(Regular Expression,简称 regex 或 regexp)是一种用特殊符号描述字符串模式的小型语言。简单说,它就是"字符串的搜索规则"。
举几个现实中的例子:
- 检查用户输入的手机号格式是否正确
- 从一段 HTML 里把所有链接提取出来
- 把文本里所有的"颜色"批量替换成"colour"
- 校验邮箱、身份证、URL 是否合法
如果用普通的字符串方法,你可能要写几十行 if-else。用正则,一行就能搞定:
// 校验是否是合法的手机号
const re = /^1[3-9]\d{9}$/;
console.log(re.test("13812345678")); // true
console.log(re.test("12345678901")); // false
二、正则的历史
正则的起源可以追溯到 1956 年,数学家 Stephen Kleene 提出了"正则语言"的形式化描述。后来 Unix 之父 Ken Thompson 把它变成了实际的工具,写出了经典的 grep。从此正则成为 Unix 文本处理的核心工具。
今天几乎所有的编程语言都内置了正则引擎:JavaScript、Python、Java、Go、PHP、Perl、Ruby……虽然各语言的实现略有差异,但核心语法是相通的。学会了正则,到哪里都能用。
三、基本语法
正则的核心是几类特殊符号,我们一类一类来看。
1. 字符类:匹配"某一类字符"
用方括号 [] 表示,匹配括号里的任意一个字符:
| 写法 | 含义 |
[aeiou] | 匹配任意一个元音字母 |
[a-z] | 匹配任意小写字母 |
[A-Z] | 匹配任意大写字母 |
[0-9] | 匹配任意数字 |
[^0-9] | 匹配任意非数字(^ 表示取反) |
[a-zA-Z0-9] | 匹配字母或数字 |
2. 预定义字符类:常用模式的简写
| 写法 | 含义 | 等价于 |
\d | 数字 | [0-9] |
\D | 非数字 | [^0-9] |
\w | 字母、数字、下划线 | [A-Za-z0-9_] |
\W | 非字母数字下划线 | [^A-Za-z0-9_] |
\s | 空白字符(空格、tab、换行) | [ \t\n\r\f] |
\S | 非空白字符 | [^ \t\n\r\f] |
. | 任意字符(除换行外) | - |
3. 量词:匹配"多少次"
| 写法 | 含义 |
* | 0 次或多次 |
+ | 1 次或多次 |
? | 0 次或 1 次 |
{n} | 正好 n 次 |
{n,} | 至少 n 次 |
{n,m} | n 到 m 次 |
例如:
\d{4}匹配 4 位数字\d{2,4}匹配 2 到 4 位数字\w+匹配一个或多个字母数字
4. 锚点:匹配"位置"而不是字符
| 写法 | 含义 |
^ | 字符串开头 |
$ | 字符串结尾 |
\b | 单词边界 |
例如:
^hello匹配以hello开头的字符串world$匹配以world结尾的字符串\bword\b只匹配完整的word单词,不会匹配password里的word
5. 分组和分支
| 写法 | 含义 | |
(abc) | 把 abc 作为一个整体 | |
| `(a | b)` | 匹配 a 或 b |
(?:abc) | 非捕获分组(不保存匹配结果) |
四、常用元字符速查表
| 元字符 | 含义 | 元字符 | 含义 | |
. | 任意字符 | ^ | 开头 | |
* | 0 次或多次 | $ | 结尾 | |
+ | 1 次或多次 | \b | 单词边界 | |
? | 0 次或 1 次 | \d | 数字 | |
{n} | 正好 n 次 | \w | 字母数字下划线 | |
[] | 字符类 | \s | 空白 | |
() | 分组 | ` | ` | 或 |
\ | 转义 | - | 范围 |
五、实战例子
例子 1:邮箱校验
const email = /^[\w.-]+@[\w-]+\.[a-zA-Z]{2,}$/;
console.log(email.test("user@example.com")); // true
console.log(email.test("user@example")); // false
解释:
^开头[\w.-]+用户名部分,允许字母数字下划线、点、短横线@必须有[\w-]+域名部分\.点[a-zA-Z]{2,}顶级域名至少 2 个字母$结尾
例子 2:手机号校验
const phone = /^1[3-9]\d{9}$/;
console.log(phone.test("13812345678")); // true
console.log(phone.test("12812345678")); // false
例子 3:提取 URL
const text = "访问 https://example.com 或 http://test.cn";
const re = /https?:\/\/[\w.-]+(?:\/[\w./-]*)?/g;
console.log(text.match(re));
// ["https://example.com", "http://test.cn"]
例子 4:替换日期格式
把 2026-07-29 替换成 29/07/2026:
const date = "2026-07-29";
const re = /(\d{4})-(\d{2})-(\d{2})/;
console.log(date.replace(re, "$3/$2/$1"));
// 29/07/2026
这里的 () 就是捕获分组,$1、$2、$3 分别引用第 1、2、3 个分组。
六、贪婪 vs 非贪婪
这是正则里一个比较反直觉的点。看下面的例子:
const html = '<div>hello</div><div>world</div>';
// 贪婪模式
const greedy = /<div>.*<\/div>/;
console.log(html.match(greedy)[0]);
// <div>hello</div><div>world</div>
// 非贪婪模式
const lazy = /<div>.*?<\/div>/;
console.log(html.match(lazy)[0]);
// <div>hello</div>
默认情况下,量词是贪婪的——会尽可能多地匹配。加一个 ? 就变成非贪婪(也叫懒惰)模式,会尽可能少地匹配。
| 量词 | 贪婪版本 | 非贪婪版本 |
* | * | *? |
+ | + | +? |
? | ? | ?? |
{n,m} | {n,m} | {n,m}? |
处理 HTML、XML 这类有嵌套结构的文本时,几乎都要用非贪婪模式。
七、为什么正则难学但必学
正则的名声不太好——很多人觉得它"像乱码一样难读"。原因主要有三个:
- 符号密集:一行里塞了几十种符号,没有变量名提示
- 同一符号在不同位置含义不同:
^在开头是锚点,在[]里是取反 - 不同语言的正则引擎有差异:JavaScript 不支持递归正则,Python 支持,PCRE 最全
但正则依然是程序员必学的基础技能,原因也很简单:
- 几乎所有文本处理场景都能用到:日志分析、数据清洗、表单校验、爬虫提取
- 学会一次,受用终身:核心语法 20 年没变过
- 写起来比手写解析代码快 10 倍:熟练后能省大量时间
- 是面试常考点:尤其是前端、后端岗位
学习建议:先把字符类、量词、锚点、分组这四类基础搞清楚,能写常见的校验正则就够了。复杂的零宽断言、反向引用等用到时再查。
八、实践推荐
写正则最痛苦的是"写出来不知道对不对",必须实时测试。在线正则工具能让你边写边看匹配结果,是学习和大批量调试时的必备:
- 正则表达式在线测试工具:https://52tool.net/tools/code/regex
支持实时高亮匹配、分组查看、常用正则库(邮箱、手机号、身份证等)、多语言代码生成,是写正则时最常打开的标签页之一。