环视:

环视的概念:环视强调的是它所在的位置,前面或者后面,必须满足环视表达式中的匹配情况,才能匹配成功,环视并不消耗正则的匹配字符,可以认为是虚拟加入到它所在__位置__的附加判断条件。

因为正则表达式是按照单个字符进行匹配的,一般情况下是从左到右,逐个匹配源字符串中的东西,当源字符串中的某个字符被匹配到以后,该字符串就不会进入下一个正则匹配的过程中,也就是说,这个字符串被消耗了。

或者,对于不消耗匹配字符还可以这么理解,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
2
regex.test('1234567891234');//false
regex.test('1234567a');//true

以上面两个表达式为例,说一下正则的匹配过程:

​ 先说正则表达式的两个特点: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}

matchexec

exec()是正则对象的一个方法,而match()是字符串的一个方法

exec()

1
exec():用给定的正则匹配指定的字符串,并返回包含查找结果的数组,返回的数组包含input和index属性。input包含被匹配的源字符串,index则声明匹配文本的第一个字符的位置;如果没有匹配到任何元素,则返回null。

exec()在匹配过程中,只会返回首次匹配到的结果,每次匹配结束后,会更新一下正则表达式的lastIndex属性,用于指向下次匹配开始时的位置。当正则表达式具有全局匹配时,看下面例子:

1
2
3
4
5
6
var re=/\d{3}/g;
var str="876jk367djf832k";
var arr = re.exec(str);//["876"]
re.lastIndex;//3
arr.index;//0
arr.input;//"876jk367djf832k"

此时,lastIndex指向索引为3的位置,说明下次匹配从索引为3的位置开始,继续匹配:

1
2
3
re.exec(str);//["367"]
re.lastIndex;//8
arr.index;//5

从3位置开始匹配,满足的匹配为"367",所以返回数组["367"],同时更新lastIndex属性为8:

1
2
3
re.exec(str);//["832"]
re.lastIndex;//14
arr.index;//11

继续从8位置开始匹配,返回满足条件的匹配["832"],并更新lastIndex属性为14,如果此时继续进行下一次匹配返回结果就是null,并且正则对象的lastIndex属性会被重置为0,然后循环上述过程。

加入正则表达式没有全局匹配标识,exec()的每次返回结果都会是一样的:

1
2
3
4
5
var re=/\d{3}/;
var str="876jk367djf832k";
re.exec(str);//["876"]
re.exec(str);//["876"]
re.exec(str);//["876"]

如果正则表达式中含有分组,也就是小括号(),并且没有全局标识,那么exec()返回的数组中,0位置为匹配到的元素,1-n为满足这些分组的子匹配,看下面例子:

1
2
3
4
5
var re=/(\d)([a-z])/;
var str="9d9g8e7m3b";
var arr = re.exec(str);//["9d", "9", "d"]
arr.index;//0
arr.input;//"9d9g8e7m3b"

match()

1
match():用给定的正则表达式对字符串进行查找,如果没有匹配结果,则返回null,否则返回包含查找结果的数组。r如果正则对象包含全局标志g,则返回的数组包含2个属性:input、index。input属性包含被查找的源字符串,index属性包含匹配结果在字符串中的位置。

看例子:

正则表达式有全局标识时,返回的结果数组不会再有indexinput属性:

1
2
3
4
5
var re=/(\d)([a-z])/g;
var str="9d9g8e7m3b";
var arr = str.match(re);//["9d", "9g", "8e", "7m", "3b"]
arr.input;//undefined
arr.index;//undefined

正则表达式无全局标识时,返回数组的第一个元素为匹配结果,剩下的元素为与正则表达式的子表达式相匹配的文本:

1
2
3
4
5
6
var re=/(\d)([a-z])/;
var str="9d9g8e7m3b";
var arr = str.match(re);
arr;//["9d", "9", "d"]
arr.input;//"9d9g8e7m3b"
arr.index;//0