正则表达式速查:从 \d 到贪婪匹配的 10 个常用套路
正则的语法不算多,但组合起来千变万化。这篇不打算讲全,只讲日常真正会用到的那 20%——以及最容易把服务器搞挂的那个坑。
基础元字符
| 写法 | 含义 | 等价于 |
|---|---|---|
\d | 任意数字 | [0-9] |
\w | 字母数字下划线 | [A-Za-z0-9_] |
\s | 空白字符 | 空格、制表符、换行 |
. | 除换行外任意字符 | — |
^ / $ | 行首 / 行尾 | — |
* + ? | 0次+ / 1次+ / 0或1次 | — |
{n,m} | n 到 m 次 | — |
[abc] | 其中任一字符 | — |
(...) | 分组 / 捕获 | — |
| | 或 | — |
记忆技巧:大写取反——\D 是非数字,\W 是非单词字符,\S 是非空白。
10 个可以直接抄的表达式
1. 邮箱(够用版) ^[\w.+-]+@[\w-]+\.[\w.]+$
2. 中国大陆手机号 ^1[3-9]\d{9}$
3. IPv4 地址 ^(\d{1,3}\.){3}\d{1,3}$
4. 中国身份证(18位) ^\d{17}[\dXx]$
5. 时间 HH:MM:SS ^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$
6. 日期 YYYY-MM-DD ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
7. 网址 ^https?://[\w.-]+(:\d+)?(/\S*)?$
8. UUID ^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$
9. 十六进制颜色 ^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$
10. 中文字符 [\u4e00-\u9fa5]
邮箱的 RFC 标准版本长到没人能看懂,实战中上面这个"够用版"已经能覆盖 99% 的场景。真要严格校验,发一封验证邮件比正则可靠得多。
贪婪 vs 惰性:最容易搞错的地方
默认情况下 * 和 + 是贪婪的——尽可能多匹配。加个 ? 变成惰性——尽可能少匹配。
文本:<b>加粗</b><i>斜体</i>
贪婪 <.+> → <b>加粗</b><i>斜体</i> (吞掉整段)
惰性 <.+?> → <b> (只匹配第一个标签)
这就是为什么"提取所有 HTML 标签"时用 <.+> 会得到一个巨大的字符串,而 <.+?> 才符合预期。
零宽断言:不消耗字符的匹配
| 写法 | 含义 |
|---|---|
(?=...) | 后面必须是(正向先行) |
(?!...) | 后面不能是(负向先行) |
(?<=...) | 前面必须是(正向后行) |
(?<!...) | 前面不能是(负向后行) |
经典用法:给数字加千分位 (?<=\d)(?=(\d{3})+$),把 1234567 变成 1,234,567,而不用捕获任何数字。
性能杀手:回溯爆炸
这个坑能把服务器 CPU 打满。看这个表达式:
^(\w+\s?)*$
输入一段正常文字没问题,但输入 aaaaaaaaaaaaaaaaaaaaaaaa!(一长串 a 加一个感叹号)时,引擎会尝试指数级的拆分组合——30 个 a 大概要算几秒,40 个 a 就要算几个小时。
这叫 ReDoS(正则拒绝服务)。防御方法:
- 避免嵌套量词:
(a+)+、(\w+\s?)*这类 - 限制输入长度(比如最长 1000 字符)
- 给正则加超时(部分语言支持)
- 用确定性的写法替代,比如
\w+(\s+\w+)*
调试建议
复杂正则不要一次写完,边写边测。用在线工具实时看匹配结果和分组,比在代码里打断点快得多——本站的正则工具会在下方实时显示所有匹配项和它们的位置。
想边写边看匹配结果?
打开正则测试工具