锚定正则表达式中如何使用负向先行断言完成URI路径合规校验
你之前写的带断言的正则失效,核心原因是负向环视仅检查它所在位置的相邻字符,不会自动扫描整个字符串:
- 放在
^后的(!--)只会校验字符串开头两个字符是不是--,如果--这类非法组合出现在字符串中间(比如foo--bar的第4、5位),这个位置的断言完全感知不到 - 放在字符组前后的断言也仅能校验对应边界的局部字符,无法覆盖全串所有可能出现连续符号的位置
- 另外你最初的断言只检查了
--这一种非法组合,没有覆盖__、-_、_-三类违规情况
下面提供两种可满足全部规则的单正则写法:
方案1:最小改动版(基于你原有正则添加全局断言)
在你原有正则的开头锚点后增加一个覆盖全串的负向先行断言,拦截所有连续符号场景即可,原有前5条规则的匹配逻辑完全保留:
^(?![0-9a-z]*[-_]{2})[a-z][0-9a-z_-]*[0-9a-z]$
逻辑说明:
新增的(?![0-9a-z]*[-_]{2})会从字符串开头扫描全串,如果任意位置出现「若干数字/小写字母后紧跟连续两个-或_」的模式,就直接判定匹配失败,刚好覆盖四类非法连续符号组合。
方案2:无环视高性能版
不需要依赖环视断言,直接按照合法字符串的结构规则编写正则,从匹配逻辑上天然规避连续符号问题,没有额外回溯开销:
^[a-z](?:[0-9a-z]|[-_][0-9a-z])+$
逻辑说明:
^[a-z]匹配首字符为小写字母,满足首字符规则(?:[0-9a-z]|[-_][0-9a-z])+要求首字符后的内容至少重复1组(总长度至少为2,满足最低长度要求),每组内容仅允许两种情况:- 普通合法字符:数字或小写字母
- 单个连接符(
-/_),且连接符后必须紧跟一个数字或小写字母——从根本上杜绝了连续两个连接符出现的可能,同时保证连接符不会出现在字符串末尾
- 整个正则仅允许小写字母、数字、
-、_四类字符,尾字符必然是数字或小写字母,自动覆盖所有规则要求
测试用例参考
- 可正常匹配:
ab、a1、a-b、a_b、foo-bar1、test_2a - 会被拦截:
a(长度不足)、-ab(首字符非法)、a-(尾字符为连接符)、a--b(连续--)、a__b(连续__)、a-_b(连续-_)、a_-b(连续_-)、aBc(含大写字母)、a@b(含非法特殊字符)
内容的提问来源于stack exchange,提问作者Dai
相关产品推荐
相关产品推荐

