1. 正则表达式基础:元字符、字符类、量词、分组与捕获
说到正则表达式,很多人第一反应就是“一堆乱码”。但我做了这么多年安全开发,可以负责任地告诉你:正则就是文本世界的瑞士军刀。你只要掌握了最核心的几个概念,后面调用DLP接口时就会发现——哦,原来都在这里。
1.1 元字符:规则的基石
元字符是正则里那些有特殊含义的符号。说白了,它们不是匹配字符本身,而是匹配“位置”或“类别”。我刚开始学的时候,老把 . 当成普通点号,结果匹配一串乱七八糟的东西——嗯,后来养成了习惯:见到元字符先转义再谈别的。
| 元字符 | 含义 | 示例 | 我的实战坑 |
|---|---|---|---|
. | 匹配除换行外的任意单字符 | a.c → abc、a_c | 注意它不匹配换行,曾经在日志解析时漏掉了跨行数据 |
^ | 匹配字符串开头 | ^Hello → 仅匹配行首的Hello | 用在多行模式时要小心 |
$ | 匹配字符串结尾 | world$ → 仅匹配行尾的world | 我踩过空行尾的坑 |
\b | 单词边界 | \bcat\b → 匹配独立单词cat | 不会匹配catalog |
\d, \w, \s | 数字、单词字符、空白 | \d+ → 连续数字 | 常用,但注意 \w 含下划线 |
小技巧:当你需要匹配一个真正的 . 时,记得在前面加反斜杠:\.。我曾经在写IP地址白名单时忘了这一步,结果把整个IP段都放行了——检修了两小时才发现。
1.2 字符类:我想要这个或那个
字符类用方括号 [] 表示,让你精确指定要匹配的一个字符范围。比如 [aeiou] 匹配任意一个元音字母。我个人习惯把常用字符类提前记在脑子里,调接口时能少查两次文档。
- 范围表示:
[a-z]小写字母,[0-9]数字,[A-F]大写A到F - 取反:
[^0-9]匹配非数字。注意这个^放在方括号里表示“不要”,放在外面才是行首 - 预定义类速查:
\d=[0-9],\w=[a-zA-Z0-9_],\s=[ \t\n\r\f]
踩过的一个大坑:字符类内部大部分元字符都会失去特殊含义,但 ]、\、^(在首位时)和 -(在中间时)需要转义。不信你试试 [a-z\.] 中的点号其实不需要反斜杠,但写了也没错。我习惯统一转义,省得脑子打架。
1.3 量词:你要匹配几个?
量词决定了前面的表达式“重复多少次”。你想想看,没有量词的正则就像只能吃一口的buffet,完全不过瘾。
| 量词 | 含义 | 示例 | 贪婪 vs 懒惰 |
|---|---|---|---|
* | 0次或多次 | ab* → a、ab、abb | 贪婪,尽可能多 |
+ | 1次或多次 | ab+ → ab、abb,但不匹配 a | 贪婪 |
? | 0次或1次 | colou?r → color 或 colour | 可用作懒惰修饰符 |
{n} | 恰好n次 | \d{3} → 三个数字 | 精确控制 |
{n,} | 至少n次 | \d{2,} → 两位以上数字 | - |
{n,m} | n到m次 | \d{2,4} → 2~4位数字 | - |
这里有个经典坑:贪婪匹配。比如你想从 <div>内容</div> 中提取内容,用了 <.*>,结果它把整个字符串都吞掉了——因为 .* 会一直匹配到最后一个 >。怎么办?加个 ? 变成懒惰模式:<.*?>。我处理XML时吃过好几次这个亏。
一句话记住:贪婪是“能多就多”,懒惰是“够用就行”。在DLP接口调用中,大部分场景推荐用懒惰量词,防止匹配越界导致敏感数据误判。
1.4 分组与捕获:把结果装进口袋
分组用圆括号 (),它有两个作用:一是把表达式当成一个整体来控制(比如 (ab)+ 匹配一个或多个 ab);二是捕获匹配到的内容,后续可以通过 \1、$1 等引用回来。
我记得之前在写邮件头解析时,要从 From: user@example.com 中提取用户名和域名。用捕获组一行搞定:
From:\s*(\w+)@(\w+\.\w+)
# \1 → user, \2 → example.com
不想捕获但又想分组?用 (?:...) 非捕获组。比如 (?:ab)+ 能控制重复,但不产生反向引用。在性能敏感的正则里,非捕获组能让引擎跑得快一点——我在批量扫描日志时改过一次,速度提升肉眼可见。
还有个名字叫“命名捕获组”的兄弟:(?<name>...)。在Python里可以 match.group('name') 取结果。代码可读性直接拉满,推荐在正则引擎调用DLP接口时使用,因为后续要对接不同的数据字段,名字比数字好记一万倍。
1.5 一张图看明白正则体系
下面这张图把前面的概念串了一下。我刚入门时就在纸上画过类似的——那时候还不会用SVG,画在草稿纸上怕弄丢还拍了张照。现在直接用代码生成,清爽多了。
1.6 正则引擎调用的实战心理准备
好了,基础概念都过了一遍。你可能会问:这些和我调DLP接口有什么关系?关系大了——DLP接口本质上接收的是“敏感数据的正则模式”。你要写正则去匹配身份证、银行卡、电话号码……如果元字符没搞懂,量词写错,分组分不清,接口返回的结果不是漏报就是误报。
我举个具体例子:某次项目中要匹配“18位身份证号”,我第一版写了 \d{18},结果把连续18个数字的订单号也报成了敏感数据。后来改成 (?<!\d)\d{18}(?!\d),用了零宽断言(下一章会讲),误报直接降了90%。
现在就开始在自己的测试环境里练手。随便拿一段文本,用本章学的元字符、字符类、量词、分组去写几个模式。别急着调接口,先跑通正则本身。我当年就是急着上线,结果正则写错了导致核心数据没匹配到——还好是测试环境,不然得被大佬请喝茶。