距离上一篇《土味正则》已经过去两年半,由于近期工作正好又用到了正则,去翻笔记才发现上一篇内容正好停更在了我正需要的查阅的内容就没了下续。
什么叫书到用时方恨少?!很多时候,我不是败给了难,而是败给了懒。对,懒散的懒,天秤与生具来的那种。小时候的夙愿就是长大最好自己什么都不用做,动动我发财的小手指就能把钱赚了。so far 码农让我“美梦成真”了……痛定思痛、开始亡羊补牢吧
需求背景
给一个软件包的package name 定义一个pattern
功能细节如下:
只能输入固定关键字
{{BSN}}
、FSP
、{{POS}}
、{{VERSION}}
、{{BETA}}
,以下划线”_
“连接,支持
1-5
个关键字,前后顺序不敏感。开头和结尾不能包含除
{{BSN}}
、FSP
、{{POS}}
、{{VERSION}}
、{{BETA}}
以外的字符keyword,大小写敏感,每种关键字
只能使用一次,不得重复使用
.
- 例如:
{{BSN}}_FSP_{{POS}}_{{VERSION}}_{{BETA}}
或{{BETA}}-FSP
需求分析
前3条实现都很好实现,也是上一篇正则中讲过的。
细节4每种关键字只能使用一次,不得重复使用
这里就要用到负向前瞻断言
。ok!下面开始上我们的主菜!
负向前瞻断言
什么是负向前瞻断言
?
负向前瞻断言
是一种正则表达式中的非捕获分组
,用于在当前位置之后查找
特定的模式,但不捕获匹配结
果。它的语法是 (?!
…),其中 … 是一个正则表达式模式。负向前瞻断言匹配的条件
是,在当前位置之后的文本中,不能匹配给定的模式。- 就好比说,每人只能只能定向分配一个小姐姐做老婆,小姐姐没出现之前整片森林都是你的。一旦正主出现后就没机会了,余生必须老老实实在自己那颗歪脖子树上好好吊着
举个🌰
假设我们要匹配不包含xiaojiejie
的字符串。我们可以使用负向前瞻断言来确保当前位置之后的文本中不包含其它xiaojiejie
。正则表达式如下:
1 | ^(?!.*xiaojiejie)[\d\w]+$ |
在这个例子中, (?!.*xiaojiejie)
用于确保在当前位置之后的文本中没有任何xiaojiejie
。否则整个正则表达式将不匹配。.*
表示一个或多个,当然,不写也可以,例如写成(?!xiaojiejie)
结果也是一样的
例如:
对于输入 “abcXYZ111”,正则表达式匹配。
对于输入 “xiaojiejie111abc”,正则表达式不匹配,因为存在小姐姐。
现在我们理解了什么是负向前瞻断言
的概要,接着我们来一起解决到上面的综合题
首先正则的格式
/^...$/
: 这是正则表达式的开始和结束锚定符,确保匹配从字符串的开头到结尾。(?!.*(?:{{BSN}}.*{{BSN}}|FSP.*FSP|{{POS}}.*{{POS}}|{{VERSION}}.*{{VERSION}}|{{BETA}}.*{{BETA}}))
: 这是一个负向前瞻断言,确保字符串中没有重复的关键字。具体来说,它防止字符串包含两次或更多相同的关键字。({{BSN}}|FSP|{{POS}}|{{VERSION}}|{{BETA}})
: 这是一个捕获组,用于匹配单个关键字。(?:_(?!.*(?:{{BSN}}.*{{BSN}}|FSP.*FSP|{{POS}}.*{{POS}}|{{VERSION}}.*{{VERSION}}|{{BETA}}.*{{BETA}})))
: 这是一个非捕获型分组,用于匹配下划线 _ 以及确保下划线后面不跟随任何重复的关键字。({{BSN}}|FSP|{{POS}}|{{VERSION}}|{{BETA}})
: 这是第二个捕获组,用于匹配第二个关键字。{0,4}
: 这是一个量词,表示前述的捕获组可以重复出现 0 到 4 次,即最多匹配五个关键字。
综上所叙 完整的正则表达式写法如下:
1 |
|
ok! 欠的作业先初到这,老衲该闭目打坐了,先行告退。Good afternoon!!
文案可能存在诸多错别字,敬请忽略!
———- ========= 我是乱入的分隔线 补充答疑环节 晚21:20==========———
文章发表后个别同仁对上面有不意见。总结几个有代表性的问题:
Q: 对上面的
?:
有些confuse 觉得无用而冗余。A : 我自己也重新review 了一下的确上面代码可以掉
?:
而且看着精简。实际上加不加在功能上是相同的、逻辑仍然是正确。这里创建非捕获型分组(`?:``),主要是为了强调这是一个非捕获型分组,并且在某些情况下,例如在处理大型文本时,可以提高正则表达式的执行效率和性能。当然你仍然可以用下面这种方式来设计你的正则
1 |
|
Q: 前后有两段相同有
({{BSN}}|FSP|{{POS}}|{{VERSION}}|{{BETA}})
和(?!{{BSN}}.*{{BSN}}|FSP.*FSP|{{POS}}.*{{POS}}|{{VERSION}}.*{{VERSION}}|{{BETA}}.*{{BETA}})
。是否能用,正则中的反向引用\1
、\2
来进一步精简代码?A: 这里要注意 反向引用
\1
、\2
等只能用于引用正则表达式中的捕获分组,而本例不是被正则表达式捕获的。因为前面的?!
断言Q: 需求中要求的是最少1次最多5次,为什么你没有写{1.5},而是{0.4}
A: 这里的{0,4} 限制的不是关键字的个数,而是了整个模式的重复次数,也就是只能重复0次时,说明已经存在了一个关键字;4次时,说明已经有5关键字了。
- 本文作者: 林杰
- 本文链接: http://linjiefe.github.io/2023/11/14/土味正则系列之二/