正则表达式从入门到实战:30分钟掌握文本处理利器
编程语言
为什么要学正则?
一行正则表达式可以替代20行字符串处理代码。
假设你要从1000行日志中提取所有IP地址。用普通代码——分割字符串、遍历、判断格式——至少20行。用正则:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3},一行搞定。
这篇教程假设你完全零基础,30分钟后你就能处理日常80%的文本匹配需求。
基础语法
字面字符和元字符
| 字符 | 含义 | 示例 |
|---|---|---|
abc |
精确匹配"abc" | hello → 匹配"hello" |
. |
任意单个字符(除换行) | h.t → hat, hot, hit |
\d |
数字 [0-9] | \d{3} → 123, 456 |
\w |
单词字符 [a-zA-Z0-9_] | \w+ → hello, test123 |
\s |
空白字符(空格、Tab、换行) | a\sb → "a b" |
\D |
非数字 | \D+ → hello |
\W |
非单词字符 | \W → @, #, ! |
量词
| 量词 | 含义 | 示例 |
|---|---|---|
* |
0次或多次 | ab*c → ac, abc, abbc |
+ |
1次或多次 | ab+c → abc, abbc(不含ac) |
? |
0次或1次 | colou?r → color, colour |
{n} |
恰好n次 | \d{4} → 四位数 |
{n,} |
至少n次 | \d{4,} → 至少四位数 |
{n,m} |
n到m次 | \d{3,5} → 三到五位数 |
字符类
[a-z] 小写字母
[A-Z] 大写字母
[0-9] 数字
[a-zA-Z] 所有字母
[^0-9] 非数字(^在[]内表示"非")
[abc] 匹配a或b或c
锚点
| 锚点 | 含义 | 示例 |
|---|---|---|
^ |
行首 | ^Hello → 以Hello开头的行 |
$ |
行尾 | world$ → 以world结尾的行 |
\b |
单词边界 | \bcat\b → 匹配独立的cat,不匹配catch |
分组和捕获
(\d{3})-(\d{4})-(\d{4}) 匹配手机号 138-0000-1111
$1 = 138, $2 = 0000, $3 = 1111
在工具库正则工具中使用替换功能:$1****$3 可以将中间四位脱敏为 138-****-1111。
非捕获分组
(?:\d{3}) 只分组不捕获,不产生$1/$2
零宽断言(进阶)
| 语法 | 含义 | 示例 |
|---|---|---|
(?=...) |
后面跟着... | \d+(?=元) → 匹配"100元"中的100 |
(?!...) |
后面不跟着... | \d+(?!元) → 不匹配"100元"中的100 |
(?<=...) |
前面是... | (?<=¥)\d+ → 匹配"¥100"中的100 |
(?<!...) |
前面不是... | (?<!¥)\d+ → 不匹配"¥100"中的100 |
实用正则配方
邮箱: [a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}
手机号: 1[3-9]\d{9}
URL: https?://[^\s/$.?#].[^\s]*
身份证: \d{17}[\dXx]
中文: [\u4e00-\u9fa5]
IP地址: \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
日期: \d{4}-\d{2}-\d{2}
常见陷阱
1. 贪婪 vs 懒惰
贪婪: <.*> 匹配"<div>hello</div>" → 整个字符串(贪心)
懒惰: <.*?> 匹配"<div>hello</div>" → 只匹配<div>和</div>
加 ? 让量词变懒惰。
2. 灾难性回溯
# 危险写法
(a+)+b 匹配"aaaaaaaaaaaaaaaaaaaa" → 性能爆炸
# 安全写法
a+b 简单明确,不嵌套量词
3. . 不匹配换行符
# 匹配多行内容
[\s\S]* 代替 .* (匹配所有字符包括换行)
动手练习
用工具库正则测试工具完成以下练习:
- 从"我的电话是138-1234-5678,办公室电话010-12345678"中提取所有电话号码
- 将"2026-06-03"替换为"06/03/2026"
- 找出文本中所有重复的单词
完成这3个练习,你就算正则入门了。搭配文本替换和文本对比功能,你的文本处理能力会上一个大台阶。
进阶配方库
日志分析专用正则
| 场景 | 正则表达式 | 说明 |
|---|---|---|
| Nginx access log | (\S+) - - \[([^\]]+)\] "([^"]*)" (\d+) (\d+) |
提取 IP、时间、请求、状态码、字节数 |
| Java 异常栈 | (\w+Exception): (.+?)\n\s+at (.+) |
提取异常类型、消息、第一个调用位置 |
| JSON 日志行 | \{[^}]+\} |
匹配单行 JSON(不含嵌套) |
| 时间戳(ISO) | \d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}[Z+-] |
ISO 8601 毫秒级别时间戳 |
| UUID | [0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12} |
标准 UUID v4 |
代码审查专用正则
| 场景 | 正则表达式 | 说明 |
|---|---|---|
| Console.log 残留 | console\.(log|warn|error|debug)\( |
查找调试代码 |
| TODO/FIXME 注释 | (TODO|FIXME|HACK|XXX): |
查找待办标记 |
| 硬编码 API Key | [A-Za-z0-9_]{20,} |
长随机字符串(疑似密钥) |
| 无异常处理的 fetch | (?<!\.catch)await fetch |
缺少 .catch() 的异步请求 |
正则标志速查
| 标志 | 含义 | 场景 |
|---|---|---|
g |
全局匹配 | 查找所有匹配项 |
i |
忽略大小写 | 大小写不敏感搜索 |
m |
多行模式 | ^ 和 $ 匹配每行首尾 |
s |
dotAll | . 也匹配换行符 |
u |
Unicode | 正确处理 emoji 和中文 |
命名捕获组
ES2018 引入的命名捕获组让正则更可读:
# 使用 ?<name> 给分组命名
(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})
在处理日期 "2026-06-30" 时:
- 传统方式:
result[1],result[2],result[3]→ 容易混淆 - 命名捕获:
result.groups.year,result.groups.month,result.groups.day→ 一目了然
在替换中使用命名引用:
${year}年${month}月${day}日 → 2026年06月30日
Unicode 与 Emoji 处理
标准 \w 只匹配 ASCII 单词字符。启用 u 标志后可以正确处理 Unicode:
// 不启用 u 标志
'你好'.match(/\w+/g) // null(不匹配中文)
// 启用 u 标志
'你好'.match(/\p{L}+/gu) // ["你好"](Unicode 字母属性)
'🎉'.match(/\p{Emoji}/gu) // ["🎉"](Emoji 属性)
// 常用 Unicode 属性
\p{L} // 任何语言的字母
\p{N} // 任何语言的数字
\p{P} // 标点符号
\p{Script=Han} // 汉字专属
本站提供浏览器本地工具,免注册即可试用 →
#正则表达式#Regex#文本处理#编程入门#开发工具