前端开发必备:常用正则表达式整理
做前端开发这么久,正则表达式绝对是我又爱又恨的工具——爱它能一行代码搞定复杂的表单验证、文本提取,恨它稍不注意就写错,调试半天找不到问题。
前阵子整理项目里的正则,发现很多网上的老正则已经过时(比如手机号段还停留在13/15开头),还有不少转义错误。今天就把我实战中验证过、修正过的常用正则全部分享出来,附详细解释和避坑指南,看完直接就能用到项目里。
一、先搞懂:正则的3个核心方法
在看具体正则之前,先快速回顾下前端最常用的3个正则方法,这是我们使用正则的基础:
| 方法 |
作用 |
示例 |
test() |
检查字符串是否匹配正则,返回布尔值 true/false |
/^1[3-9]\d{9}$/.test('13812345678') |
match() |
在字符串中查找匹配的内容,返回匹配结果数组(无匹配返回 null) |
'abc123def'.match(/\d+/) → ['123'] |
replace() |
替换字符串中匹配的内容,返回新字符串 |
'a b c'.replace(/\s+/g, ' ') → 'a b c' |
小技巧:正则字面量(/正则/)比 new RegExp('正则') 更常用,因为不用处理双转义的问题(比如 \d 在字符串里要写成 \\d)。
二、身份信息类:表单验证最常用
这是项目里用得最多的场景,身份证、手机号、邮箱、邮编,一个都不能少。
1. 身份证号码(15位/18位)
身份证正则不仅要校验长度,还要校验年份、月份、日期的基本格式,最后一位校验位(X/x)也要支持。
1 2 3 4 5 6 7 8 9 10 11 12
| const idCard15 = /^[1-9]\d{7}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}$/;
const idCard18 = /^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$/;
const idCard = /(^[1-9]\d{7}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}$)|(^[1-9]\d{5}(19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}[\dXx]$)/;
console.log(idCard.test('110101199003077758')); console.log(idCard.test('110101900307775'));
|
⚠️ 避坑指南:
- 正则只能校验格式,不能校验身份证的真实性(比如校验位是否正确、地区码是否存在)。如果需要严格校验,建议配合校验算法(比如ISO 7064:1983.MOD 11-2)使用。
- 注意年份限制:上面的18位正则只支持1900-2099年,这已经能覆盖绝大多数场景了。
2. 中国大陆手机号(2024年最新号段)
手机号段更新很快,现在不仅有13/15/17/18/14开头,还有16/19开头的新号段,正则必须跟上。
1 2 3 4 5 6 7 8 9 10
| const phone = /^1[3-9]\d{9}$/;
const phoneWithArea = /^(\+86|0086)?1[3-9]\d{9}$/;
console.log(phone.test('13812345678')); console.log(phone.test('19912345678')); console.log(phoneWithArea.test('+8613812345678'));
|
⚠️ 避坑指南:
- 不要写太复杂的号段细分(比如
13[0-9]|15[0-35-9]|...),号段更新太快,维护成本太高。用 1[3-9]\d{9} 覆盖所有1开头的11位数字,是最稳妥的方案。
- 如果需要区分移动/联通/电信,再单独写细分正则,但一般业务场景不需要。
3. 邮箱地址
邮箱正则要覆盖常见格式:用户名@域名.后缀,支持用户名里的 +.-_ 等特殊字符。
1 2 3 4 5 6
| const email = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
console.log(email.test('user_name+tag@example.co.uk')); console.log(email.test('user.name@example.com'));
|
⚠️ 避坑指南:
- 没有100%覆盖所有RFC标准的邮箱正则(太复杂,性能也差),上面的正则能覆盖99.9%的实际场景。
- 不要用正则限制邮箱长度,RFC标准允许邮箱最长254个字符。
4. 中国邮政编码
6位数字,第一位不为0。
1 2 3 4
| const zipCode = /^[1-9]\d{5}$/;
console.log(zipCode.test('430000'));
|
三、日期时间类:格式校验必备
日期格式校验很常见,要支持常见的 YYYY-MM-DD、YYYY/MM/DD、HH:mm:ss 等格式。
1. 日期(YYYY-MM-DD 或 YYYY/MM/DD)
1 2 3 4 5 6
| const date = /^(19|20)\d{2}([-\/])(0[1-9]|1[0-2])\2(0[1-9]|[12]\d|3[01])$/;
console.log(date.test('2024-05-20')); console.log(date.test('2024/05/20'));
|
2. 时间(HH:mm:ss 或 HH:mm)
1 2 3 4 5 6 7 8 9
| const time = /^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$/;
const timeSimple = /^([01]\d|2[0-3]):[0-5]\d$/;
console.log(time.test('14:30:00')); console.log(timeSimple.test('14:30'));
|
3. 日期时间(YYYY-MM-DD HH:mm:ss)
1 2 3 4
| const dateTime = /^(19|20)\d{2}([-\/])(0[1-9]|1[0-2])\2(0[1-9]|[12]\d|3[01]) ([01]\d|2[0-3]):[0-5]\d:[0-5]\d$/;
console.log(dateTime.test('2024-05-20 14:30:00'));
|
⚠️ 避坑指南:
- 正则只能校验格式,不能校验逻辑合理性(比如2024-02-30、2024-04-31这种无效日期)。如果需要严格校验,建议用
Date 对象或者 day.js/moment.js 等日期库。
四、数字类:金额、整数、小数全覆盖
1. 整数(支持正负数)
1 2 3 4 5 6 7 8 9 10 11 12
| const integer = /^[-+]?\d+$/;
const positiveInteger = /^[1-9]\d*$/;
const negativeInteger = /^-[1-9]\d*$/;
console.log(integer.test('-123')); console.log(positiveInteger.test('123'));
|
2. 浮点数(小数,支持正负数)
1 2 3 4 5 6 7 8 9
| const float = /^[-+]?(\d+(\.\d*)?|\.\d+)$/;
const strictFloat = /^[-+]?\d+\.\d+$/;
console.log(float.test('.45')); console.log(strictFloat.test('123.45'));
|
3. 金额(保留2位小数,支持千分位)
1 2 3 4 5 6
| const money = /^[-+]?(\d{1,3}(,\d{3})*|\d+)(\.\d{2})?$/;
console.log(money.test('12,345.67')); console.log(money.test('1234.56'));
|
五、文本提取类:爬虫、数据清洗常用
1. URL链接
1 2 3 4 5 6
| const url = /^(https?:\/\/|ftp:\/\/)?([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}(:\d+)?(\/[a-zA-Z0-9-._~:/?#[\]@!$&'()*+,;=]*)?$/;
console.log(url.test('https://www.example.com/path?query=123#hash')); console.log(url.test('ftp://ftp.example.com'));
|
2. 图片链接(常见后缀)
1 2 3 4 5
| const imgUrl = /^https?:\/\/.*\.(jpg|jpeg|png|gif|webp|bmp)$/i;
console.log(imgUrl.test('https://example.com/image.JPG'));
|
3. 中文字符串
1 2 3 4 5 6 7 8 9
| const chinese = /^[\u4e00-\u9fa5]+$/;
const hasChinese = /[\u4e00-\u9fa5]/;
console.log(chinese.test('你好世界')); console.log(hasChinese.test('你好hello'));
|
4. 去除字符串首尾空格
虽然现在有 String.prototype.trim(),但用正则实现也很经典:
1 2
| const trim = /^\s+|\s+$/g; ' hello world '.replace(trim, '');
|
六、其他常用正则
1. 用户名(字母开头,字母数字下划线,4-16位)
1 2 3 4
| const username = /^[a-zA-Z][a-zA-Z0-9_]{3,15}$/;
console.log(username.test('user_123'));
|
2. 密码强度(至少8位,包含大小写字母、数字、特殊字符)
1 2 3 4 5
| const strongPassword = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%^&*])[a-zA-Z\d!@#$%^&*]{8,}$/;
console.log(strongPassword.test('Abc123!@'));
|
3. QQ号码(5-11位数字,不以0开头)
1 2 3 4
| const qq = /^[1-9]\d{4,10}$/;
console.log(qq.test('123456789'));
|
七、避坑指南:正则的5个常见坑
1. 转义字符的坑
在正则字面量里,\d 表示数字,但如果用 new RegExp() 字符串写法,必须双转义成 \\d:
1 2 3 4 5 6 7 8
| const reg1 = /\d+/;
const reg2 = new RegExp('\\d+');
const reg3 = new RegExp('\d+');
|
建议:优先用正则字面量,避免转义问题。
2. 贪婪匹配 vs 懒惰匹配
正则默认是贪婪匹配(尽可能多匹配),在量词后面加 ? 变成懒惰匹配(尽可能少匹配):
1 2 3 4 5 6 7
| const str = '<div>hello</div><div>world</div>';
str.match(/<div>.*<\/div>/);
str.match(/<div>.*?<\/div>/);
|
3. 正则的性能问题
复杂的正则(比如大量嵌套、回溯)会导致性能问题,甚至页面卡顿:
- 避免写太复杂的正则,能拆分成多个小正则就拆分;
- 避免用
.* 这种大范围匹配,尽量用具体的字符范围;
- 合理使用
^ 和 $ 锚点,减少不必要的匹配。
4. 不要过度依赖正则
正则不是万能的:
- 身份证校验位、日期逻辑合理性,用算法或日期库更靠谱;
- HTML/XML解析,用DOM解析器(比如
DOMParser)比正则更安全;
- 复杂的语法解析,用专门的解析器。
5. 修饰符的使用
常用修饰符:
i:不区分大小写(/abc/i 匹配 ABC、Abc);
g:全局匹配(/a/g 匹配所有 a,而不是只匹配第一个);
m:多行匹配(^ 和 $ 匹配每一行的开头和结尾)。
八、写在最后
正则表达式是前端开发的利器,但也是一把双刃剑——用得好能事半功倍,用不好会带来无数调试噩梦。
我的建议是:
- 优先用成熟的正则(比如本文整理的这些),不要自己瞎写;
- 写好后多测试边界情况(比如空字符串、特殊字符、超长字符串);
- 复杂场景配合工具库使用(比如日期用day.js,密码强度用zxcvbn)。