正则表达式中的test、exec、match
环视:
环视的概念:环视强调的是它所在的位置,前面或者后面,必须满足环视表达式中的匹配情况,才能匹配成功,环视并不消耗正则的匹配字符,可以认为是虚拟加入到它所在__位置__的附加判断条件。
因为正则表达式是按照单个字符进行匹配的,一般情况下是从左到右,逐个匹配源字符串中的东西,当源字符串中的某个字符被匹配到以后,该字符串就不会进入下一个正则匹配的过程中,也就是说,这个字符串被消耗了。
或者,对于不消耗匹配字符还可以这么理解,
RegExp
对象都有一个lastIndex
属性,这个属性表示下一次匹配的开始位置,而对于环视来讲,当进行到环视的匹配时,正则表达式的lastIndex
不会改变。
我的理解,环视限制了它所在位置能有什么和不能有什么,注意,这里强调的是__位置__。
环视主要有四种,分别如下:
- 顺序肯定环视
(?=exp)
- 顺序否定环视
(?!exp)
- 逆序肯定环视
(?<=exp)
- 逆序否定环视
(?<!exp)
环视的使用
看一下环视如何使用,下面的正则表达式:
var regex=/^(?![a-z]+$)(?![A-Z]+$)(?!\d+$)[a-zA-Z\d]{8,12}/
来解析一下上面的正则表达式:
(?![a-z]+$)
:?!
表示顺序否定环视,表示该位置不能有什么。现在这个表达式放在开头,说明开头位置不能全是小写字母;
(?![A-Z]+$)
:表示不能全是大写字母;
(?!\d+$)
:表示不能全是数字;
[a-zA-Z\d]{8,12}
:匹配到这里,由于环视不消耗匹配字符,所以此时的lastIndex
仍然为0,也就是说[a-zA-Z\d]{8,12}
匹配时仍然从源字符串的开头开始匹配,所以总的来说,上面的正则匹配的是–至少包含大写字母、小写字母、数字中的两种,并且长度为8~12位。
正则匹配的过程
1 | regex.test('1234567891234');//false |
以上面两个表达式为例,说一下正则的匹配过程:
先说正则表达式的两个特点:1、默认情况下匹配都是贪婪的;2、引擎会返回最先匹配到的结果
第一个例子:首先(?![a-z]+$)
会去匹配,是否全是小写字母,lastIndex
此时为0,该位置字符串为1
,所以匹配结果是true
;接着(?![A-Z]+$)
再去匹配,是否全是大写字母,1
不是大写字母,返回结果–不是,接下来(?!\d+$)
进行匹配,从索引0位置开始,1
是数字,不符合不全是数字的条件,所以将lastIndex
后移一位,接下来要匹配的是12
,仍然不满足不全是数字的条件,所以,继续后移lastIndex
,直到最后一位,匹配的字符串1234567891234
依然不满足不全是数字的条件,这时已经尝遍了所有可能的情况,依然不满足条件,所以整个匹配结果返回false
。
第二个例子:对于(?![a-z]+$)
和(?![A-Z]+$)
的匹配情况和第一个例子一样,直接来看(?!\d+$)
的匹配。从0位置到6位置匹配结果一直是false
,当lastIndex
移动到6位置时,由于出现了一个小写字母a
从而满足了不全是数字的条件,所以匹配通过。接下来,前面三个环视匹配的结果会作为一个范围送给[a-zA-Z\d]{8-12}
去匹配,这时候要求只能是数字、小写字母、大写字母,长度必须在8~12之间,所以最终的匹配结果是true
。
http://xz.jb51.net:81/201101/books/jtregex3_jb51.7z 精通正则表达式
?!
:预判,从当前位置到尾部预览字符串
密码强度:
8位字母数字的组合,至少包含一位大写字母和一位数字
预判: 从头到尾预览字符串
1. 不全由字母组成: (?![a-zA-Z]+$)
结论: 至少包含一位数字,还可能有特殊符号
2. 不全由小写字母和数字组成: (?![0-9a-z]+$)
结论: 至少包含一位大写字母,还可能包含特殊符号
3. 只能由字母和数字组成: [0-9A-Za-z]{8}
排除特殊符号的可能
(?![a-zA-Z]+$)(?![0-9a-z]+$)[0-9A-Za-z]{8}
match
和exec
exec()
是正则对象的一个方法,而match()
是字符串的一个方法
exec()
1 | exec():用给定的正则匹配指定的字符串,并返回包含查找结果的数组,返回的数组包含input和index属性。input包含被匹配的源字符串,index则声明匹配文本的第一个字符的位置;如果没有匹配到任何元素,则返回null。 |
exec()
在匹配过程中,只会返回首次匹配到的结果,每次匹配结束后,会更新一下正则表达式的lastIndex
属性,用于指向下次匹配开始时的位置。当正则表达式具有全局匹配时,看下面例子:
1 | var re=/\d{3}/g; |
此时,lastIndex
指向索引为3的位置,说明下次匹配从索引为3的位置开始,继续匹配:
1 | re.exec(str);//["367"] |
从3位置开始匹配,满足的匹配为"367"
,所以返回数组["367"]
,同时更新lastIndex
属性为8:
1 | re.exec(str);//["832"] |
继续从8位置开始匹配,返回满足条件的匹配["832"]
,并更新lastIndex
属性为14,如果此时继续进行下一次匹配返回结果就是null
,并且正则对象的lastIndex
属性会被重置为0,然后循环上述过程。
加入正则表达式没有全局匹配标识,exec()
的每次返回结果都会是一样的:
1 | var re=/\d{3}/; |
如果正则表达式中含有分组,也就是小括号()
,并且没有全局标识,那么exec()
返回的数组中,0位置为匹配到的元素,1-n
为满足这些分组的子匹配,看下面例子:
1 | var re=/(\d)([a-z])/; |
match()
1 | match():用给定的正则表达式对字符串进行查找,如果没有匹配结果,则返回null,否则返回包含查找结果的数组。r如果正则对象包含全局标志g,则返回的数组包含2个属性:input、index。input属性包含被查找的源字符串,index属性包含匹配结果在字符串中的位置。 |
看例子:
正则表达式有全局标识时,返回的结果数组不会再有index
和input
属性:
1 | var re=/(\d)([a-z])/g; |
正则表达式无全局标识时,返回数组的第一个元素为匹配结果,剩下的元素为与正则表达式的子表达式相匹配的文本:
1 | var re=/(\d)([a-z])/; |