问题
正则表达式是什么?常见语法有哪些?写正则时最容易踩哪些坑?
回答
核心结论
正则表达式可以理解为一套“文本匹配规则”,常用于:
- 校验输入格式
- 提取文本中的目标片段
- 批量替换内容
- 在日志、配置、代码中做模式搜索
它的优势是表达紧凑,缺点是可读性容易快速下降,所以实际使用中要坚持两个原则:
- 能写清楚就不要写太花
- 能做粗校验就不要假装做强校验
基础语法速查
| 符号 | 含义 | 示例 |
|---|---|---|
. |
默认匹配除换行外的任意单个字符 | a.c 可匹配 abc、a1c |
* |
前一个模式重复 0 次或多次 | ab*c 可匹配 ac、abbc |
+ |
前一个模式重复 1 次或多次 | ab+c 可匹配 abc、abbbc |
? |
前一个模式重复 0 次或 1 次 | colou?r 可匹配 color、colour |
^ |
字符串开头 | ^hello |
$ |
字符串结尾 | world$ |
| ` | ` | 或 |
字符类与常用简写
| 写法 | 含义 |
|---|---|
[abc] |
匹配 a、b、c 中任意一个 |
[a-z] |
匹配任意小写字母 |
[^0-9] |
匹配任意非数字字符 |
\d |
数字 |
\w |
字母、数字、下划线 |
\s |
空白字符 |
\D |
非数字 |
\W |
非字母数字下划线 |
\S |
非空白字符 |
量词
| 量词 | 含义 |
|---|---|
{n} |
恰好 n 次 |
{n,m} |
n 到 m 次 |
{n,} |
至少 n 次 |
*? |
懒惰匹配 |
+? |
懒惰匹配 |
分组与捕获
(ab)+
含义:把 ab 当作一个整体,整体重复一次或多次。
常见分组有两类:
(...):捕获组,后续可以读取匹配结果(?:...):非捕获组,只分组,不关心保存结果
捕获示例(Python)
import re
text = "电话:138-1234-5678"
pattern = r"(\d{3})-(\d{4})-(\d{4})"
match = re.search(pattern, text)
print(match.group(1))
print(match.group(2))
print(match.group(3))
输出依次是:
13812345678
贪婪与懒惰
<.*>
默认是贪婪匹配,会尽可能多吃字符。
例如在 <b>hi</b> 上,<.*> 可能一次吞掉整个字符串。
如果你只想匹配最短的一段,通常改成:
<.*?>
这就是懒惰匹配。
常见示例
1. 纯数字
^[0-9]+$
表示整段字符串只能由数字组成。
2. 提取文件扩展名
\.([a-zA-Z0-9]+)$
3. 粗略校验邮箱
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$
这个表达式适合前端表单或简单文本过滤,但不适合当作严格的邮箱合法性校验规则,因为真实邮箱规则远比它复杂。
最容易踩的坑
| 坑点 | 说明 |
|---|---|
误以为 . 真的是“任意字符” |
很多引擎默认不匹配换行 |
| 忘记转义 | 想匹配点号时应该写 \. |
| 贪婪匹配过头 | .* 很容易吃掉比预期更多的内容 |
| 把正则当万能解析器 | HTML、SQL、复杂语法树通常不适合只靠正则解析 |
| 忽略语言差异 | Java、Python、JavaScript 在转义和特性支持上存在差异 |
一句话总结
正则表达式本质上是“文本匹配规则”,适合做搜索、提取和粗校验;写得越短不一定越好,写得越清楚才越实用。
相关问题
^和$有什么用? → 用来限制匹配范围,避免只命中字符串的一部分。- 为什么有时候一个正则在 Python 能用,在 JavaScript 里不一样? → 因为不同语言的正则引擎和字符串转义规则存在差异。
- 遇到复杂正则怎么排查? → 先拆成小段逐步验证,再确认是不是贪婪、转义或边界符写错了。
技术拓展
一个很实用的写法思路
把复杂正则拆成“片段思维”:
开头约束 + 主体模式 + 分隔符 + 结尾约束
例如邮箱粗校验可以拆成:
- 开头:
^ - 用户名:
[a-zA-Z0-9._%+-]+ - 分隔符:
@ - 域名:
[a-zA-Z0-9.-]+ - 顶级域:
\.[a-zA-Z]{2,} - 结尾:
$
这样比直接死记整串表达式更容易维护。