这几天在深入学习正则,今天对一个需求进行深入分析,需求是这样的:“匹配三个字符igm的随机组合,但是不能重复”。
刚看到这个需求的时候是一脸懵逼的,如果仅从题面出发,我们枚举一下就可以:
/(i|g|m|(ig)|(gi)|(im)|(mi)|(gm)|(mg)|(img)|(igm)|(mgi)|(mig)|(gmi)|(gim))?$/
这样也太没技术含量了吧,而且如果需求改成四个字母,五个字母呢?看我用“零宽断言”实现一下下,于是乎:
/^((?<char>[img])(?!.*\k<char>))*$/
首先“零宽断言”的作用就是“站在一个位置往 前/后 可以/不可以 匹配其中的模式”,语法如下:
/(?=pattern)/ // 当前位置往前匹配pattern
/(?<=pattern)/ // 当前位置往后匹配pattern
/(?!pattern)/ // 当前位置往前不匹配pattern
/(?<!pattern)/ // 当前位置往后不匹配pattern
因此,看上面正则后半部分(?!.*\k<char>)
即表示“从当前位置开始往后不应当匹配/.*\k<char>/
这样的pattern”,其中\k<char>
代表前面名为“/(?<char> ... )/
”分组匹配到的字符。
在看前面那部分(?<char>[img])
即i
、m
、g
组成的字符集,且成一个分组,名为char。
这个语法暂时还未完全兼容,等价正则为
/^(([img])(?!.*\2))*$/
那这部分表示的含义就是:“匹配img中任意一个字符,且从当前位置往后,不再匹配到这个字符(不重复)”。
然后,再外面一层*
表示这个pattern匹配0次或0次以上。
最后,为保证只包含igm三个字符,加上^
和$
表示完整匹配整个字符串。
给出可视化图如下:
(本篇完)