两种匹配语义
部分匹配问的是「串里有没有符合模式的一段」,全串匹配问的是「整串是否完全符合模式」。两者在提取场景差别不大,在校验场景却是天壤之别:部分匹配会把非法输入判为合法。
实现方式有三类
一是用专门的整串匹配接口,二是给模式加首尾锚点,三是先部分匹配再比较长度。三者都可以,但整串接口最不容易出错,因为它把约束放在调用方式上,而不是依赖模式里两个容易被忽略的符号。
基本信息
| 整串接口 | 多数语言提供专门的整串匹配方法,语义清晰 |
|---|---|
| 锚点写法 | 模式首尾加绝对或行锚点,需注意末尾换行的宽松判定 |
| 长度校验 | 部分匹配成功后比较返回片段长度是否等于输入长度 |
| 库函数差异 | 有的语言最常用的入口是部分匹配,例如匹配字符串的接口本身不做整串约束 |
| 命令行场景 | 逐行处理的工具天然把每行当独立输入,仍需注意空白与行尾字符 |
| 推荐顺序 | 优先整串接口,其次绝对锚点,最后才考虑长度比较 |
典型使用场景
- 表单字段格式校验,要求输入整段合规而不是含有一段合规内容
- 解析定长或定结构字段,确认没有多余前后缀
- 校验主机名、路径、编号等不允许夹带额外字符的字段
- 排查校验被绕过的问题:确认用的到底是部分匹配还是整串匹配
- 把提取与校验拆成两次调用,分别使用更合适的语义
校验写法的正确姿势
校验写法的正确姿势
import re
re.search(r'\d{4}', 'abc2026def') # 部分匹配:非法输入也可能通过
re.fullmatch(r'\d{4}', 'abc2026def') # 整串匹配:这里返回失败
re.fullmatch(r'\d{4}', '2026') # 合规输入正常通过
re.search(r'\A\d{4}\Z', '2026') # 用绝对锚点达到同样效果
re.search(r'^\d{4}$', '2026') # 行锚点写法,末尾换行时判定较宽松
m = re.search(r'\d{4}', '2026')
print(m and len(m.group(0)) == len('2026')) # 退而求其次的长度校验匹配语义选择
| 场景 | 合适的语义 | 原因 |
|---|---|---|
| 字段校验 | 整串匹配 | 必须排除多余内容 |
| 关键字搜索 | 部分匹配 | 只关心是否存在 |
| 结构化提取 | 部分匹配加遍历 | 逐个取出所有片段 |
| 严格解析 | 整串匹配加分组 | 同时保证结构与取值 |
换语言时最容易踩的坑是入口函数语义变了:同样的调用在某个语言里是整串匹配,在另一个语言里却是部分匹配。迁移代码时先把这一点确认清楚,再谈模式细节。
需要同时校验并取值时,用整串匹配接口配合捕获分组即可一次完成。分成两次调用虽然可行,但容易出现两次规则漂移不一致的问题。