教你怎么理解正则表达式之零宽断言(环视)

前端之家收集整理的这篇文章主要介绍了教你怎么理解正则表达式之零宽断言(环视)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

思考题

今天有人问一个关于零宽断言的正则:

var reg = /(?=a)b/;
reg.exec("ab");

大家思考下这个正则为什么匹配不了?我们先了解一下什么叫零宽断言,最后再来回答这个问题。

概念理解

零宽断言(有的资料叫它环视),分为零宽度正预测先行断言( 格式为 (?=exp) ),和零宽度正回顾后发断言( 格式为 (?<=exp) )。javascript目前只支持前者,所以这里我们只以前者来讨论。(为了便于表述,下文所出现的“零宽断言”或“断言”如果不特别说明,都指前者。)

我们先从字面上来理解下。零宽度,说明它是不占字符宽度的,只是一个位置,它不匹配任何东西。但是这个“位置”跟 ^ $ \b 这三个东东是有本质区别的。还是很难理解?好吧,先略过,相信看完本文你会理解的。接下来,正预测,这个很好理解,就是表示这个表达式是一种预测,预测接下来会发生的情况。最后,先行断言,意即提前确定。结合起来,就是:我断言,在我所在的位置后面,必然要出现我所表达的东西

说了一大堆,很多人还是云里雾里吧,那么,下面这段代码就来加深你的理解:

var reg = /(?=abc)\w\w\w123/;
reg.exec("abc123"); // 结果 abc123
reg.exec("dbc123"); // 结果 null

我们结合这段代码来看,我们用了一个零宽断言(?=abc),它断言了在它出现的位置接下来的三个字符必须是abc,意即我断言接下来的\w\w\w(当然,实际应用中不会写这么笨的代码,可以写成\w{3},这里只是为了便于加深理解)三个字符必须为abc。所以这里,第一个结果能够匹配abc123,而第二个结果则显示匹配不到任何东西。零宽断言就是一种预言,它告诉表达式,接下来会发生什么。

但是问题也来了:“零宽断言不是不匹配任何东西吗?那这里第一个结果怎么匹配了abc?” 对,没错,这个表达式是匹配到了abc,但是,并不是(?=abc)匹配的呀,而是后面的\w\w\w匹配到的,我只是预测了\w\w\w将会是abc不是吗?

应用场景

说到这里,不少人会问了:我用 /abc123/ 不就可以匹配了吗?用你这个正则的意义何在?

没错,这个正则把简单的问题复杂化了。但是存在的,就是有意义的。实际使用中,零宽断言(再次强调这里单指零宽度正预测先行断言)多用在匹配它之前的内容,而不是之后的内容。怎么理解呢?请看代码

var reg = /abc(?=123)/;
reg.exec("abc123"); // 结果 abc
这里,我的零宽断言放在abc之后,也就是说,我断言abc之后必然要出现123。但是断言不是匹配——我只是预测将要出现的东西,我不匹配任何东西(这就是 零宽度的意义)。所以,匹配结果为 abc。
上面说的是匹配它之前的内容的情况,那么匹配它之后的内容的情况就完全没有意义了吗?No!请看下例:
/^(?=^.{8,}$)(?=.*\d)(?=.*\W+)(?=.*[A-Z])(?=.*[a-z])(?!.*\n).*$/

这个看起来比较复杂,是一个js群里的人发的,一个十分巧妙的正则。不过,分解开来其实一点也不复杂,这是由五个零宽断言和一个负向零宽断言(负向表否定)组成。前五个分别是:必须是8位以上、必须出现数字、必须出现特殊符号(非字母数字下划数)、必须出现大写字母、必须出现小写字母。最后一个负向零宽断言是:不得出现换行。大家会发现每个断言都是以 .* 开头,那这个表示什么意思呢?因为这些断言都是写在同一位置,而同一位置是不可能同时出现以上六种情况的。所以用 .* 来告诉表达式,这个断言之前可以有字符(意即这个断言可以出现在接下来的字符串任何位置)。那么这条正则表达式有什么作用呢?有做过密码验证的同学马上就反应过来了,这可以用来做强密码验证。

最后的一些唠叨

现在再回过头来看看之前的思考题,是不是一下子就明白了问题所在?(?=a) 断言了它后面必须出现a,但是紧接着的表达式却给了一个b,很显然,这个表达式本身就是不成立的。

那么,做一下修改 /(?=a)\wb/ 不就成立了吗?可是,我之所以用零宽断言,就是想要匹配b呀,不想匹配a呀。那既然这个断言不能满足,我该怎么办呢?

对于这种情况,那我们就不该用零宽度正预测先行断言(?=exp),而是该用零宽度正回顾后发断言(?<=exp)了。

var reg = /(?<=a)b/;
reg.exec("ab"); // 结果 b
不过很可惜,目前javascript是不支持这种断言的(ps.好像好多语言都不支持吧 ^-^),所以以上的代码只存在于理论中,无法在js环境中运行。

猜你在找的正则表达式相关文章