JavaScript正则表达式

参考资源
https

1介绍正则表达式

1.1 正则表达式

正则表达式广泛的用于计算机领域内的编程和运维等各个子领域,用于匹配字符串的一些特殊字符。
web开发本质上是处理字符串(服务端接受请求处理后拼接字符串作为响应,这在早期的CGI编程中最明显,然后客户端解析字符串进行渲染和执行)。js作为web开发的关键语言,同样需要充分利用正则表达式。

1.2 正则表达式的优越性

如何在一个字符串里获得其中的所有连续的数字子字符串。例如字符串"asdfa123asd78"需要返回一个数组,数组的长度为2,元素分别为123,78。
1.面向过程的思想,写一个函数,循环遍历这个字符串的每一个字符。如果这个字符是数组,保留下来,并判断能否继续和后面的字符一起组成一个更长的数字。如果这个字符不是数字,那就把之前保留下来的数字字符串放到结果数组里。
2.用正则表达式匹配。

		var fun1=function(str){
			var tmp="";
			var result=[];
			for(var i=0;i<str.length;i++){
				var achar=str[i]
				if(!isNaN(achar))//如果这个字符是数字,存在tmp里等待其他数字字符的加入
					tmp+=achar;
				else{//如果这个字符不数字,前面的tmp如果有数字,把之前的认为就是一个结果
					if(tmp){//如果这个数字字符串不是空的
						result.push(tmp);
						tmp="";
					}	
				}
				}
			if(tmp){//如果数字字符串在最后一段上
				result.push(tmp);
			}
			return result;//返回搜索的数组
		}
		//1.使用自定义的方法
		var str="asdfa123asd78";
		console.log(fun1(str));
		//2.使用正则表达式
		console.log(str.match(/\d+/g));

2 正则表达式的创建和使用

2.1 创建正则表达式

1.创建正则表达式对象
var 变量=new RegExp(字符串,修饰符)根据提供的字符串创建正则表达式对象
2.简化的正则表达式对象的写法
var 变量=\正则语法\修饰符
例如下面的创建匹配数字字符的正则表达式

        var reg1=new RegExp("\\d+","g");//数字,注意需要两个斜杠才能够表示数字,因为js;里没有原生字符串的机制
        var reg2=/\d+/g;
        console.log(reg1);
        console.log(reg2);

2.2 使用正则表达式

 var str="abc123def567";
        var reg1=new RegExp("\\d+","g");//数字,注意需要两个斜杠才能够表示数字,因为js;里没有原生字符串的机制

1.正则表达式的方法
2.字符串的方法,正则表达式作为参数。
都在后面。

2.3 正则表达式的属性与修饰符

1.属性

属性描述
constructor返回一个函数,该函数是一个创建 RegExp 对象的原型。
global判断是否设置了 “g” 修饰符
ignoreCase判断是否设置了 “i” 修饰符
lastIndex用于规定下次匹配的起始位置
multiline判断是否设置了 “m” 修饰符
source返回正则表达式的匹配模式

2.修饰符

修饰符描述
i执行对大小写不敏感的匹配。
g执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)。
m执行多行匹配。

3 正则表达式的语法规则

3.1 普通字符

正则表达式由普通字符和元字符表示,普通字符就是普通的字符串。

3.2 实意元字符

1.如下表

字符描述
\.任意字符
\d匹配一个数字字符。等价于 [0-9]。
\D匹配一个非数字字符。等价于 [^0-9]。
\f匹配一个换页符。等价于 \x0c 和 \cL。
\n匹配一个换行符。等价于 \x0a 和 \cJ。
\r匹配一个回车符。等价于 \x0d 和 \cM。
\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]。
\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
\t匹配一个制表符。等价于 \x09 和 \cI。
\v匹配一个垂直制表符。等价于 \x0b 和 \cK。
\w匹配字母、数字、下划线。等价于’[A-Za-z0-9_]’。
\W匹配非字母、数字、下划线。等价于 ‘[^A-Za-z0-9_]’。

2.基本的使用
例如下面创建一个匹配两个连续数字字符的对象,成功与失败。

            var reg=new RegExp("\\d\\d");//两个连续的数字字符
            str1="123abc";
            console.log(str1.match(reg));//Array(1)
            str2="1abc";
            console.log(str2.match(reg));//none

3.注意事项:
在使用字符串创建正则表达式的实意元字符时,需要使用两个连续的反斜杠(简写的正则表达式只需要写一个反斜杠),
第一个斜杠表示后面的反斜杠是真实有意义的,第二个反斜杠才表示正则表达式里的斜杠。
例如创建匹配单个数字字符的正则表达式对象

            var reg=new RegExp("\\d");//两个连续的数字字符
           var reg2=/\d/

3.3 字符集元字符

1.如下表

字符描述
x|y匹配 x 或 y。例如,'z
[xyz]字符集合。匹配所包含的任意一个字符。例如, ‘[abc]’ 可以匹配 “plain” 中的 ‘a’。
[^xyz]负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]’ 可以匹配 “plain” 中的’p’、‘l’、‘i’、‘n’。
[a-z]字符范围。匹配指定范围内的任意字符。例如,’[a-z]’ 可以匹配 ‘a’ 到 ‘z’ 范围内的任意小写字母字符。
[^a-z]负值字符范围。匹配任何不在指定范围内的任意字符。例如,’[^a-z]’ 可以匹配任何不在 ‘a’ 到 ‘z’ 范围内的任意字符。

2.基本用法

			str="12ab34deGH"
            var reg1=new RegExp("ab|de",'g');//匹配字符ab或者de
            console.log(str.match(reg1));//Array(2) {0: "ab" 1: "de" length: 2}
            var reg2=new RegExp("[abde]",'g');//匹配字符a或b或d或e
            console.log(str.match(reg2));//Array(4) 0: "a" 1: "b" 2: "d" 3: "e" length: 4
            var reg3=new RegExp("[a-z]",'g');//所有小写字母
            console.log(str.match(reg3));//Array(4) 0: "a" 1: "b" 2: "d" 3: "e" length: 4
            var reg4=new RegExp("[a-zA-Z]",'g');//所有字母
            console.log(str.match(reg4));//Array(6) 0: "a" 1: "b" 2: "d" 3: "e" 4: "G" 5: "H"
            var reg5=new RegExp("[^a-zA-X]",'g');//所有非字母
            console.log(str.match(reg5));//Array(4) 0: "1" 1: "2" 2: "3" 3: "4" length: 4

3.注意数量元字符在这里失效了。
例如下面的[]里的+表示为符号+而不是数量词。这是因为[]表示从里面选择一个,数量词+?*{}表示重复,即使表示数量,也没有用,因此为了使用在[]直接使用数量词元字符就是字符的效果。

            // 数量元字符失效,他表示为符号本身的意思
            str="12ab+34de+GH"
            var reg=new RegExp("[a-z+]",'g');
            console.log(str.match(reg));//Array(6) 0: "a" 1: "b" 2: "+" 3: "d" 4: "e" 5: "+" length: 6

4.特殊的字符集匹配|的作用
把|前面的或者后面的都看作一个整体,选择前面的或者后面的。

3.4 数量词元字符

1.如下表

字符描述
*匹配前面的子表达式零次或多次。例如,zo* 能匹配 “z” 以及 “zoo”。* 等价于{0,}。
+匹配前面的子表达式一次或多次。例如,‘zo+’ 能匹配 “zo” 以及 “zoo”,但不能匹配 “z”。+ 等价于 {1,}。
?匹配前面的子表达式零次或一次。例如,“do(es)?” 可以匹配 “do” 或 “does” 。? 等价于 {0,1}。
{n}n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}’ 不能匹配 “Bob” 中的 ‘o’,但是能匹配 “food” 中的两个 o。
{n,}n 是一个非负整数。至少匹配n 次。例如,‘o{2,}’ 不能匹配 “Bob” 中的 ‘o’,但能匹配 “foooood” 中的所有 o。‘o{1,}’ 等价于 ‘o+’。‘o{0,}’ 则等价于 ‘o*’。
{n,m}m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,“o{1,3}” 将匹配 “fooooood” 中的前三个 o。‘o{0,1}’ 等价于 ‘o?’。请注意在逗号和两个数之间不能有空格。
?当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串 “oooo”,‘o+?’ 将匹配单个 “o”,而 ‘o+’ 将匹 配所有 ‘o’。

2.基础的用法

            var str="12345abc024689"
            var reg1=new RegExp("\\d+","g");//位数大于1的数字
            console.log(str.match(reg1));//Array(2) 0: "12345" 1: "024689"
            var reg2=new RegExp("\\d?","g");//没有数字或者单个数字
            console.log(str.match(reg2));//Array(15)
            //0: "1" 1: "2" 2: "3" 3: "4" 4: "5" 5: "" 6: "" 7: ""
            //8: "0" 9: "2" 10: "4" 11: "6" 12: "8" 13: "9" 14: ""
            var reg3=new RegExp("\\d*","g");//没有数字或任意位数的数字
            console.log(str.match(reg3));//Array(6)0: "12345" 1: "" 2: "" 3: "" 4: "024689" 5: ""
            var reg4=new RegExp("\\d{5}","g");//5位数字
            console.log(str.match(reg4));//Array(2) 0: "12345" 1: "02468"
            var reg5=new RegExp("\\d{5,6}","g");//5或6位数字
            console.log(str.match(reg5));//Array(2) 0: "12345" 1: "024689"

可以发现
?和*时会出现空字符,这是因为?和*允许不出现制定内容,即允许出现空字符,而默认任意两个具体的字符之间没有字符,就认为两个任意字符之间就是空字符。因此使用?和*需要注意必要的时候过滤掉空字符。
3.扩展的用法
(1)通过各种数量词元字符,就可以实现强大的数量模糊匹配,即字符数符合某个条件。
例如下式匹配连续的大于4位的数字

            var str2="123abc4567def987654";
            var reg=new RegExp("\\d{4}\\d*","g");//匹配连续的大于4位的数字
            console.log(str2.match(reg))//Array(2) 0: "4567" 1: "987654" length: 2

(2)一般情况下,数量词只会对前面的一个字符有效,如果我们想要匹配多个字符重复,就需要使用括号。
例如下式匹配连续两次的ab.字符

            var str3="abcabd2abe";
            var reg=new RegExp("(ab.){2}","g");
            console.log(str3.match(reg))//Array(1) 0: "abcabd" length: 1

4.贪婪匹配与非贪婪匹配
(1)什么叫贪婪匹配
从2中的例子里面我们发现正则表达式的数量元字符会匹配尽可能多的字符。上面的2的*例子,发现他会匹配24689而不是某个其中的单个字符,这种匹配的方法称为贪婪匹配,即最大可以匹配多少字符那就匹配多少字符。
下面这个也是一个贪婪匹配的实例:
+会尽量的匹配更多的重复,这种就叫做贪婪匹配

			var str4="abcabd2abe";
            var reg=new RegExp("(ab.)+","g");
            console.log(str4.match(reg));//Array(2)0: "abcabd" 1: "abe" length: 2

2.取消贪婪匹配模式,即非贪婪匹配模式,,在表示数量词的元字符后面加上?表示非贪婪匹配。
例如下式与上面的正则表达式极其相似,只是多了个?就表示为非贪婪匹配。

var str4="abcabd2abe";
            var reg=new RegExp("(ab.)+?","g");//非贪婪匹配
            console.log(str4.match(reg));// Array(3) 0: "abc" 1: "abd" 2: "abe" length: 3

3.5 分组元字符

1.如下表

字符描述
(pattern)匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0…$9 属性。要匹配圆括号字符,请使用 ‘(’ 或 ‘)’。
(?:pattern)匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 “或” 字符 (
(?=pattern)正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)“能匹配"Windows2000"中的"Windows”,但不能匹配"Windows3.1"中的"Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?!pattern)正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如"Windows(?!95|98|NT|2000)“能匹配"Windows3.1"中的"Windows”,但不能匹配"Windows2000"中的"Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。
(?<=pattern)反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。例如,"(?<=95|98|NT|2000)Windows"能匹配"2000Windows"中的"Windows",但不能匹配"3.1Windows"中的"Windows"。
(?<!pattern)反向否定预查,与正向否定预查类似,只是方向相反。例如"(?<!95|98|NT|2000)Windows"能匹配"3.1Windows"中的"Windows",但不能匹配"2000Windows"中的"Windows"。

2.基本用法
就是用来提高优先级的。
(1)我们在这里先了解一下正则表达式的优先级的概念。
正则表达式从左到右进行计算,并遵循优先级顺序,这与算术表达式非常类似。
相同优先级的从左到右进行运算,不同优先级的运算先高后低。下表从最高到最低说明了各种正则表达式运算符的优先级顺序:

运算符描述
\转义符
(), (?: ), (?=), []圆括号和方括号
*, +, ?, {n}, {n,}, {n,m}限定符
^, $, \任何元字符、任何字符定位点和序列(即:位置和顺序)
|替换,"或"操作
字符具有高于替换运算符的优先级,使得"mfood"匹配"m"或"food"。若要匹配"mood"或"food",请使用括号创建子表达式,从而产生"(m|f)ood"。

举例说明:用()提升优先级

		//提升优先级
        //\\d\\w{2}只会匹配11a,23b这样的字符
        var reg=new RegExp("(\\d\\w){2}","g");//1a1b 2b3r这样的字符
        var str="1a1badsfa2b3r";
        console.log(str.match(reg));//Array(2)0: "1a1b"1: "2b3r"length: 2

3.如果由括号还会影响函数调用后的数组情况,这一点在后面的正则表达式函数介绍。
4.预查匹配:不仅要求结果的字符串满足一些条件,他旁边的字符也应该满足一些条件。
例如我想匹配Windows的系统版本例如Windows98或者WindowsXP或者Windows10等等。而不像查找像Windows3.4这样的东西但我只要其中的Windows,这就叫做预查匹配。
(1)正向预查:正向表示判定表达式与前面的字符组合。

        var str="Windows98,WindowsXP,Windows10,Windows4.3,Windows5.7";
        //正向肯定预查
        var reg=new RegExp("Windows(?=98|XP|10)","g");
        console.log(str.match(reg));//匹配了前三个Windows
        //正向否定预查
        var reg=new RegExp("Windows(?!98|XP|10)","g");
        console.log(str.match(reg));//匹配后面两个Windows

(2)反向预查,反向表示判定表达式与后面的字符结合。

        var str="98Windows,XPWindows,10Windows,4.3Windows,5.7Windows";
        //反向肯定
        var reg=new RegExp("(?<=98|XP|10)Windows","g");
        console.log(str.match(reg));//匹配了前三个Windows
        //反向否定
        var reg=new RegExp("(?<!98|XP|10)Windows","g");
        console.log(str.match(reg));//匹配了前三个Windows

3.6 边界匹配与换行匹配。

1.如下表

属性描述
\b匹配一个单词边界,也就是指单词和空格间的位置。例如, ‘er\b’ 可以匹配"never" 中的 ‘er’,但不能匹配 “verb” 中的 ‘er’
\B匹配非单词边界。‘er\B’ 能匹配 “verb” 中的 ‘er’,但不能匹配 “never” 中的 ‘er’。
^匹配输入字符串的开始位置。如果设置了 RegExp 对象的 Multiline 属性,^ 也匹配 ‘\n’ 或 ‘\r’ 之后的位置。
$匹配输入字符串的结束位置。如果设置了RegExp 对象的 Multiline 属性,$ 也匹配 ‘\n’ 或 ‘\r’ 之前的位置。

2.单词边界

        str="ia ib    ic\t id";
        reg0=new RegExp("\\bi.\\b","g");
        console.log(str.match(reg0));//句子开头,句子结尾,空格,\t都算作边界
        // Array(4)
        // 0: "ia"
        // 1: "ib"
        // 2: "ic"
        // 3: "id"

3.字符串边界
(1)没有multiline属性
如果遇到多行,只会匹配整个字符串的开头和结尾i。

        //没有修饰符m,如果字符串是多行字符串的话,只会对第一行进行匹配操作。
        var str="This is a word";
        var reg1=new RegExp("^This .{5}");//要求匹配的内容必须在开头
        console.log(str.match(reg1));//
        // Array(1)
        // 0: "This is a "
        var reg2=new RegExp(".{5} word$");//要求匹配的内容必须在结尾
        console.log(str.match(reg2));//
        // Array(1)
        // 0: " is a word"
        var reg3=new RegExp("^This .* word$")//
        console.log(str.match(reg3));
        // Array(1)
        // 0: "This is a word"
        //有修饰符m,会对每一i行进行匹配操作,每一行的开头、结尾都可以认为是开头结尾。

(2)有multiline属性
如果遇到多行,会匹配每行字符串的开头和结尾i。

        //有修饰符m,会对每一i行进行匹配操作,每一行的开头、结尾都可以认为是开头结尾。
        var str="This is a word \nThis is china";
        var reg4=new RegExp("^This .{5}","gm");//要求匹配的内容必须在开头,一般m和g搭配使用表示在每行上匹配开头或结尾。也可以单独使用。
        console.log(str.match(reg4));//
        // Array(2)
        // 0: "This is a "
        // 1: "This is ch"

4 常用的正则表达式方法

4.1 正则表达式的方法

1.如果有全局匹配修饰符g,正则表达式的lastindex属性会记录每次匹配成功后的位置。
(1)test方法和exec方法每次都会尝试寻找一个成功的匹配。如果查找成功了,test返回true,exec方法返回一个数组对象(这个数组对象有一些额外的属性),并且记录此时的查找下标。
(2)再次调用test或exec方法时从这个下标位置开始查找,如果查找失败test返回false,exec方法返回null。并且把下标位置置0.
(3)即使是不同的字符串,正则表达式都会从lastindex开始查找,因此,对不同的字符串用正则表达式匹配,需要事先手动把lastindex属性置为0。

var str="abc123def567";
        var reg1=new RegExp("\\d+","g")
        //对于加了g修饰符的
        // 1.判断是否能够匹配成功,在字符串中存在成功匹配的子字符串
        console.log(reg1.test(str));//true
        console.log(reg1.lastIndex);//6下标
        // 2.返回第一个成功匹配的结果
        console.log(reg1.exec(str));//456
        // Array(1)
        // 0: "567"
        // groups: undefined
        // index: 9
        // input: "abc123def567"
        // length: 1
        console.log(reg1.lastIndex);//12下标
        console.log(reg1.exec(str));//null
        console.log(reg1.lastIndex);//0小标
        console.log(reg1.exec(str));//123,又从头开始了
        console.log(reg1.lastIndex);//6

2.如果没有全局匹配修饰符g,正则表达式的lastindex属性不会记录每次匹配成功后的位置,一直是0,下一次匹配还是从头开始找一个。

             // 没有加g修饰符的
        // 1.判断是否能够匹配成功,在字符串中存在成功匹配的子字符串
        var str="abc123def567";
        var reg2=new RegExp("\\d+")
        console.log(reg2.test(str));//123
        console.log(reg2.lastIndex);//0
        // 2.返回第一个成功匹配的结果
        console.log(reg2.exec(str));//123
        console.log(reg2.lastIndex);//0
        console.log(reg2.exec(str));//123
        console.log(reg2.lastIndex);//0

4.2 字符串match,search方法

(1)有全局修饰符g.match方法返回一个数组,每一项是从头开始的一个成功的匹配结果,search方法返回从头开始的第一个成功匹配的索引,没有成功的匹配结果的话返回-1。
match方法会改变正则表达式对象lastIndex属性,search方法不会。

        var str="abc123def567";
        var reg1=new RegExp("\\d+","g")
         // 1.match方法,返回匹配结果数组
        console.log(str.match(reg1));
        // Array(2)
        // 0: "123"
        // 1: "567"
        // length: 2
        // 2.search方法,返回第下标为0开始的成功匹配的结果所在的索引
        console.log(str.search(reg1));//3

(2)没有全局修饰符g。search方法与reg.exec效果相同,总是获得第一个匹配成功对象。search方法总是返回第一个匹配成功对象的索引,没有成功的匹配结果的话返回-1。

4.3 字符串replace方法 split方法

有没有g效果都相同。

// 3.replace方法,用指定字符串替换第一个成功匹配的结果.
        console.log(str.replace(reg1,"*"))
        // 4.split方法,在每一次成功匹配的结果的位置做分割
        console.log(str.split(reg1))

4.6 方法与分组。

reg.exec方法和str.match方法,如果有分组的话,会对这两个方法的效果产生影响。

 //如果正则表达式没有分组,这个数组就只有一项,表示第一次成功匹配的结果
        //有分组,那么数组就不止一项
        var str="abc123abf567";
        var reg0=new RegExp("ab(.)");
        //没有g修饰,效果相同,每次都是匹配开头往后第一个结果结果相同,exec方法与match方法相同。。
        console.log(str.match(reg0));//数组第一个元素是整个成功匹配结果,其余都是分组的匹配结果
        console.log(reg0.exec(str));//数组第一个元素是整个成功匹配结果,其余都是分组的匹配结果
        // Array(2)
        // 0: "abc"
        // 1: "c"


        //有g修饰
        var reg0=new RegExp("ab(.)","g");
        console.log(str.match(reg0));//数组的每一个元素都是成功匹配的结果。
        console.log(reg0.exec(str));//数组第一个元素是整个成功匹配结果,其余都是分组的匹配结果
        // Array(2)
        // 0: "abc"
        // 1: "c"
        console.log(reg0.exec(str));//数组第一个元素是整个成功匹配结果,其余都是分组的匹配结果
        // Array(2)
        // 0: "abf"
        // 1: "f"

可以在分组是用(?:模式)表示这个分组只表示优先级,没有实际意义,这样就可以避免出现上面的情况了。
2.分组的命名与编号。
此处待补充。

5 正则表达式使用策略

综上所述,正则表达式像火星文一样,格式复杂,想要完全透彻理解正则表达式有些困难。
起步阶段我们需要认真研究每个正则表达式,熟练以后我们就可以直接使用辅助工具了。
这里推荐菜鸟教程的在线测试工具
https://c.runoob.com/front-end/854
还有一款程序员编码助手软件。
彗星小助手。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值