正则表达式是程序员工具箱中最强大的文本处理武器。学会它之前,你靠 split 和 substring 手工拆字符串。学会之后,一行表达式就能解决以前需要 20 行代码的问题。代价是:它看起来像来自另一个星球的语言。

基础语法速查

元字符 含义 示例
. 匹配任意单字符 h.t -> hat, hot, hit
* 0 次或多次 ab*c -> ac, abc, abbc
+ 1 次或多次 ab+c -> abc, abbc(不含 ac)
? 0 或 1 次 colou?r -> color, colour
{n} 恰好 n 次 a{3} -> aaa
{n,} n 次或更多 a{2,} -> aa, aaa, aaaa
{n,m} n 到 m 次 a{2,4} -> aa, aaa, aaaa
[abc] 字符组 gr[ae]y -> gray, grey
[^abc] 否定字符组 [^0-9] -> 非数字
\d 数字 等价于 [0-9]
\w 单词字符 [a-zA-Z0-9_]
\s 空白字符 空格、制表符、换行
^ 行首 ^Hello
$ 行尾 end$
() 捕获组 (\d{3})-(\d{4})

贪婪 vs 非贪婪

这是初学者最容易踩的坑。默认 * 和 + 都是贪婪模式——尽可能多地匹配。加 ? 变成非贪婪(懒惰)模式——尽可能少地匹配。

对于

Hello
:<.*> 贪婪匹配整个字符串(到最后一个 >)。<.*?> 非贪婪只匹配第一个
。匹配 HTML 标签时永远用非贪婪模式。

零宽断言(Lookahead/Lookbehind)

零宽断言匹配位置而非字符——不消耗字符,只检查条件。

断言 含义 示例
(?=…) 正向前瞻 \d+(?=元) -> 100元中的100
(?!…) 负向前瞻 \d+(?!元) -> 不跟元的数字
(?<=…) 正向后顾 (?<=¥)\d+ -> ¥100中的100
(?<!…) 负向后顾 (?<!¥)\d+ -> 不含¥前缀的数字

捕获组与反向引用

括号不但用于分组,还会捕获匹配内容供后续使用。\1、\2 等反向引用可以引用之前捕获的内容——这对于匹配重复模式极其有用:

匹配重复单词:(\w+) \1 匹配 hello hello、test test。
匹配成对标签:<(\w+)>.*?</\1> 匹配

标志(Flags)

标志 含义
g 全局匹配(找所有而非第一个)
i 忽略大小写
m 多行模式(^$ 匹配每行首尾)
s 单行模式(. 也匹配换行符)
u Unicode 模式

实战场景

日志解析: 从 Nginx 日志中提取 IP 和状态码。
表单验证: 邮箱 ^[\w.-]+@[\w-]+.[a-z]{2,}$、手机号 ^1[3-9]\d{9}$、URL、密码强度。
代码重构: 批量替换变量名、提取函数签名、格式化不一致的日期格式。

调试工具

推荐 regex101.com——实时显示匹配结果、捕获组内容、提供解释和性能分析。是学习和调试正则的最佳工具。

总结

正则表达式的学习曲线确实陡峭,但回报同样巨大。掌握元字符基础、理解贪婪陷阱、灵活运用零宽断言和捕获组——你就拥有了处理任意文本格式的超能力。多练习、多用 regex101 调试,它最终会成为你敲得最快的代码。