字符匹配与元字符:点号、字符集、预定义字符类
正则表达式的核心能力,说白了就是「模式匹配」。你写一个模式,它去文本里找符合的片段。元字符就是这些模式的「积木块」。本章我们专门讲三个最基础的:点号、字符集、预定义字符类。掌握它们,你就能写出大部分日常需要的正则了。
点号(.):匹配任意单个字符
点号是最简单的元字符。它匹配除了换行符以外的任意单个字符。我早期刚学正则时,总觉得它就是个通配符——很像 shell 里的 ?,但它只占一个位置。
举个例子:
模式:h.t
匹配:hat、hot、hit、h2t、h%t
不匹配:heat(字符数不对)、h\nt(换行符)
我在处理日志文件时,经常用它来匹配「日期分隔符不统一」的情况。比如 2024-01-01 和 2024/01/01,用 2024.01.01 就能一把抓。当然要注意,点号不会匹配换行。如果你需要匹配包括换行在内的任意字符,那就用 (.|\n) 或者 [\s\S](后面会讲到)。
.+ 去匹配整行,结果因为贪婪匹配把不该吞的内容也吞了。后来才意识到,能用字符集精确匹配的地方,尽量不要用点号。
字符集([]):指定一组候选字符
字符集用方括号包裹。它匹配括号内出现的任意一个字符。说白了,就是「或」的关系,但写法干净很多。
[abc] 匹配 a、b、c 中的任意一个
[0-9] 匹配 0 到 9 之间的任意数字
[a-zA-Z] 匹配所有大小写字母
连字符 - 在字符集里表示「范围」。你想想看,写 [0-9] 比写 [0123456789] 优雅多了。不过要注意,- 放在开头或结尾时,它就只是一个普通连字符,不会产生范围。
我个人习惯将字符集用于「固定长度的可选模式」。比如校验手机号前三位:1[3-9] 就可以匹配 13、14、15…19 开头。这个比写 1(3|4|5|6|7|8|9) 更直观。
^,比如 [^0-9] 匹配任意非数字字符。注意:这个 ^ 只能在字符集内部生效,放在外部就是匹配行首了,别搞混。
预定义字符类:快捷方式
为了少打字,正则里给你备好了几个常用字符类的缩写。我刚开始用的时候记错了不少次,后来画了张表贴在屏幕上才搞定。
| 预定义类 | 等价于 | 说明 |
|---|---|---|
\d |
[0-9] |
匹配任意数字(digit) |
\D |
[^0-9] |
匹配任意非数字 |
\w |
[a-zA-Z0-9_] |
匹配字母、数字、下划线(word character) |
\W |
[^a-zA-Z0-9_] |
匹配非单词字符 |
\s |
[ \t\n\r\f\v] |
匹配空白字符(space、制表符、换行等) |
\S |
[^ \t\n\r\f\v] |
匹配非空白字符 |
为什么要单列预定义类?因为效率。我记得有一次在 10GB 的日志里做匹配,用 \d 比 [0-9] 快了一点点——引擎内部有优化。而且写出来更简洁。比如提取 IP 地址:
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
看着不舒服?其实 \d{1,3} 指的是「匹配 1 到 3 个数字」,这个我们后面章节会细讲。现在你只要能理解 \d 的含义就行。
\D、\W、\S)永远是小写上对应的「取反」。记住这个规律,你就不用死记硬背了。
三者对比:什么时候用谁?
很多初学者会问:点号、字符集、预定义类,到底选哪个?嗯,我一般按这个优先级决定:
- 优先用预定义类:比如
\d或\w,写起来最快,语义明确。 - 其次用字符集:当预定义类不能精确描述时,比如只要大写字母
[A-Z],或者只要某些特定符号[+*%]。 - 最后才用点号:只有当你真的不在乎具体是什么字符时才用点号。说白了,点号是「懒人救星」,但容易误伤。
我曾经在写一个数据清洗脚本时,遇到一行格式很乱,用 .+? 想偷懒,结果把相邻字段给吞了。最后老老实实改用 [^,]+ 按逗号分割,才解决。所以结论是:能精确就别模糊。
知识体系流程图
避坑与实战技巧
刚用正则时,我踩过这些坑,今天分享给你:
- 转义元字符:如果你想匹配真正的点号
.,必须写成\.。否则点号会被当成元字符。同理,[、]、\都需要转义。我记得刚开始写匹配文件名的正则,一直匹配不上,查了半天才发现 .png 里的点没转义。 - 字符集内的特殊字符:在
[]内部,^只在开头取反,其他地方是普通字符;-表示范围,最好放在开头或结尾避免歧义;\仍然需要转义。 - 预定义类的边界:
\w包含下划线,如果你只想要字母数字,就用[a-zA-Z0-9]。曾经有同事用\w+匹配用户名,结果包含了下划线导致校验出了问题。 - 点号和换行:大多数正则引擎中,点号默认不匹配换行。如果你需要匹配跨行内容,要么开启
s修饰符(DotAll),要么用[\s\S]来替代点号。