这几天在深入学习正则,今天对一个需求进行深入分析,需求是这样的:“匹配三个字符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])img组成的字符集,且成一个分组,名为char。

这个语法暂时还未完全兼容,等价正则为/^(([img])(?!.*\2))*$/

那这部分表示的含义就是:“匹配img中任意一个字符,且从当前位置往后,不再匹配到这个字符(不重复)”。

然后,再外面一层*表示这个pattern匹配0次或0次以上。

最后,为保证只包含igm三个字符,加上^$表示完整匹配整个字符串。

给出可视化图如下:

igm

(本篇完)


书籍推荐