正则表达式能否匹配定长token串中指定token出现指定次数的子串?
问题解答
该匹配需求完全可以通过支持前瞻断言的现代正则引擎实现,无需额外编写分词、计数逻辑。
针对固定长度token的匹配场景,不需要提前对字符串做分词切割,利用固定字符长度定位token边界、配合零宽断言做计数校验,即可精准命中符合要求的子串,同时支持重叠子串的匹配。
针对给定场景的实现方案
基础参数说明
本次场景固定参数如下:
- 单token长度
d=4 - 首尾边界token间距
N=4(即首尾token之间共4个token,匹配子串总长度为6个token共24字符) - 起始边界token:
SbbE - 结束边界要求:不得为
SbtE(注:原测试串中对应排除、统计目标实际为StbE,属于笔误,以下正则以测试用例实际可命中预期结果的StbE为统计/排除目标,若需匹配SbtE直接替换对应字面量即可) - 区间内目标token(
StbE)出现次数要求:k=2到N=4次
可直接使用的正则表达式
开启全局匹配模式下,使用以下正则即可命中所有符合要求的子串,捕获组1的内容即为匹配结果:
(?=(SbbE(?=(?:.{4})*?(?:StbE(?:.{4})*?){2,4}(?!.{4}StbE)).{16}(?!StbE).{4}))
正则逻辑拆解
- 外层
(?=())为零宽正向前瞻结构,匹配时不会消耗字符串字符,可支持重叠子串的捕获,避免漏掉位置靠后的重叠匹配结果 - 开头的
SbbE用于锚定符合要求的起始边界token - 内嵌的前瞻断言
(?=(?:.{4})*?(?:StbE(?:.{4})*?){2,4}(?!.{4}StbE))用于计数校验:从起始token之后开始,以4字符为一个token单位遍历,确认区间内StbE的出现次数在2-4次区间内,且不存在更多符合的token .{16}用于匹配首尾边界之间的4个token(4字符*4=16字符),严格限定两个边界的间距- 末尾的
(?!StbE).{4}用于匹配结束边界token:先断言接下来4个字符不是被排除的StbE,再匹配这4个字符作为子串的结束边界
匹配结果验证
针对测试字符串s = "SbbESbbESbbEStbEStbESbbEStbESttE",上述正则的捕获结果共2条,和预期完全一致:
- 第1-6个token构成的子串:
SbbESbbESbbEStbEStbESbbE,区间内StbE出现2次,结束token为SbbE符合要求 - 第3-8个token构成的子串:
SbbEStbEStbESbbEStbESttE,区间内StbE出现3次,结束token为SttE符合要求
通用适配规则
如果需要调整参数适配其他同类场景,只需按规则替换正则内对应部分即可:
- 调整单token长度
d:将正则中匹配单个token的.{4}替换为.{<d值>} - 调整边界间距
N:将匹配中间区间长度的.{16}替换为.{<d值*N值>} - 调整出现次数区间:将计数部分的
{2,4}替换为{<k值>,<N值>} - 调整起始、结束、待统计token:直接替换正则中对应的字面量字符串即可
内容的提问来源于stack exchange,提问作者Sia
相关产品推荐
相关产品推荐

