Article
正则表达式常用校验模板速查(附踩坑说明)
用之前先说三件事
- 不要用正则验证邮箱的全部合法性。RFC 5322 允许的正则长达数百字符且仍有争议,实践中用「有 @、有域名、有点」的宽松版本即可,真正的验证靠发信。
- 正则只做格式校验,不做业务校验。手机号正则通不过校验器,不代表这个号真实存在。
- 前后端都要校验。前端正则负责体验,后端负责安全。
下面所有模板都可以在 正则测试工具 里直接粘贴验证。
高频模板
1. 中国大陆手机号
^1[3-9]\d{9}$
1[3-9] 覆盖现有号段开头,\d{9} 补足 11 位。注意:\d 在 JavaScript 里只匹配 ASCII 数字,但 \d 在部分语言(如 Python 的 re 用 str 模式时)可能匹配 Unicode 数字,跨语言移植时要加 re.ASCII。
2. 邮箱(宽松版,推荐)
^[\w.+-]+@[\w-]+(\.[\w-]+)+$
[\w.+-]+ 允许 a.b+c@ 这种合法写法;(\.[\w-]+)+ 要求至少一个点。
别用这个「严格版」:
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
它会拒绝 user@localhost 和一些 IDN 域名,实际业务里只会带来客诉。
3. URL
^https?:\/\/[^\s]+$
用 [^\s]+ 而不是 .+,避免跨行匹配。要校验 https 强制,把 s? 去掉。
4. IPv4
^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)$
每段限 0~255,且不允许前导零(192.168.01.1 不通过)。IPv6 不要用正则,用 inet_pton 之类的解析函数。
5. 日期 YYYY-MM-DD(含基本合法性)
^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
它只校验「月 01-12、日 01-31」,不校验 2 月 30 日这种不存在日期。要严格校验,解析成 Date 再比对。
6. 时间 HH:mm:ss(24 小时制)
^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$
7. 金额(最多两位小数)
^\d+(\.\d{1,2})?$
不允许负数、不允许 1,000.00 这种带千分位的输入——千分位应在展示层处理,不要和校验混在一起。
8. 身份证(18 位,简化)
^\d{17}[\dXx]$
末位可能是校验码 X。真实校验要算 ISO 7064:1983 MOD 11-2 校验位,正则做不到。
9. 密码强度(至少 8 位,含大小写与数字)
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$
注意:这条正则只检查「包含」,不检查「不包含」。真正该做的是计算熵,见 密码怎么设才安全。
10. 去首尾空白(替换用)
^\s+|\s+$
或者更省事的 /^\s+|\s+$/g 一次性替换为空串。多数语言有更快的 trim(),别用正则做这件事。
三个真实踩坑
坑一:贪婪匹配吃掉不该吃的内容
输入:<a href="x">link</a>
正则:<a href=".*">
结果:<a href="x">link</a> ← 整段都被吃掉了
把 .* 换成 .*?(懒惰)即可:
<a href=".*?">
坑二:回溯爆炸(ReDoS)
^(a+)+$
对 aaaaaaaaaaaaaaaaaaaaaaX 这种输入,引擎会尝试指数级的组合,直接把 CPU 打满。同理还有 (\w+\s?)*。
规则:避免「嵌套量词」,尤其是 (X+)+ 这种形式。用户可控的输入上跑复杂正则,必须先做长度限制和超时保护。
坑三:Unicode 边界
想匹配「所有中文」,很多人写 [\u4e00-\u9fa5]。它只覆盖 BMP 中常用汉字,漏掉扩展区汉字(如 𠀀 这类生僻字、部分人名用字)。
更稳的写法(需 u 标志):
\p{Script=Han}
/^\p{Script=Han}+$/u.test('中文')
类似地:\w 不匹配中文;\b 对中文的「词边界」判断不可靠,不要用它做中文分词。
一个可用的检查流程
- 在 正则测试工具 里先跑「应该匹配」的样本
- 再跑「不该匹配」的样本(这一步最容易被跳过)
- 用超长/畸形输入压一遍,看会不会卡死
- 把正则和「为什么这么写」的注释一起提交,半年后你会感谢自己
相关:统计待处理文本的长度和行数,可以用 文本字数统计。