![93d34097a6708d1810d243d5181a67ad.png](https://i-blog.csdnimg.cn/blog_migrate/7f06102fa0e779c68e4319be37900d18.jpeg)
点击上方蓝字关注我们
之前的文章:
JavaScript正则表达式的模式匹配教程,并且附带充足的实战代码(一)
我们继续来学习正则表达式吧,没有看过之前文章的小伙伴建议点击上方链接,从第一篇开始看,本系列文章适合从未接触过或不太了解正则表达式的人
重复
上一篇我们讲到了字符类,本文就从重复开始讲。
在上一部分,我们知道字符类都是匹配一个字符,例如 /\d/
和 /[0-9]/
都是匹配任意一个数字 、/[abcd]/
也是匹配一个字符,那如果我们想要匹配多个字符串岂不是要写很多遍重复代码?例如我们要匹配一个三位数字的字符串,我们就需要设置这样一个匹配模式 /\d\d\d/
。其实正则表达式有几种语法,可以将该表达方式简化,我们来看一下这个表格
字符 | 匹配 |
{n, m} | 匹配前一项n-m次 |
{n, } | 匹配前一项至少n次 |
{n} | 匹配前一项n次 |
? | 匹配前一项0次或1次,相当于{0,1} |
+ | 匹配前一项至少一次,相当于{1,} |
* | 匹配前一项0次或更多次,相当于{0,} |
我们接下来就利用这些语法进行一下重复操作,例如我们要匹配一段字符串中的11位数字,我们可以这样写 /\d{11}/
,因为\d
表示的是任意数字,在它后面加上一个重复语法,就是重复\d
多少次。我们如果要匹配一个三位的字母并且后面跟上一个一位的可选数字,我们可以这样 /[a-zA-Z]{3}\d?/
,[a-zA-Z]{3}
表示匹配任意三位字母,\d?
表示匹配数字0次或1次
重复是贪婪的,它们会尽可能的多地匹配,我们称之为贪婪的重复,下面来看一个例子
let pattern = /\d{3,10}/let str = "0123456789"str.match(pattern)[0] //返回 0123456789
这里介绍一个新的匹配方法 match
,它可以将匹配到的一段字符串放在一个数组里,若没匹配到则返回null。 在这个例子中,我们设置的匹配模式是/\d{3,10}/
,表示匹配数字3到10次,因为重复语法默认是贪婪的,它会尽可能多地匹配,所以他就匹配了任意数字10次,返回 0123456789
。
那么如果我们如何使他们不贪婪地重复呢?其实很简单,我们只需要在重复的语法后面加一个 ?
即可将重复变成非贪婪的,还是这个例子
let pattern = /\d{3,10}?/let str = "0123456789"str.match(pattern)[0] //返回 012
这是我们可以看到,在重复语法 {3,10}
后面加上一个 ?
以后,它并没有尽可能多地匹配了,而是变成了尽可能少地匹配,即匹配三次任意数字就结束匹配。
还有其他的非贪婪重复的语法有: ??
、+?
、*?
,你们可以下去自行测试
选择
在JavaScript中有一个运算符可以用在正则表达式中,那就是 |
,它的意思就是或者,例如这个例子 /[a-z]|[0-9]/
意思就是可以匹配任意一个a-z的字母,或者也可以匹配任意一个0-9的数字。
在复杂的例子里,我们也可以这样使用,先给出需求,匹配一段字符串,它可以是3位的不区分大小写的字母,也可以是4位的数字
let pattern = /[a-zA-Z]{3}|\d{4}/let str = "Lpyexplore2333"str.match(pattern)[0] //返回 Lpy
在这个例子中,我们匹配的模式是3位的不区分大小写的字母或者4位数字,但是 str 中既有3位的不区分大小写的字母,也有4位数字,为什么最后只是返回了Lpy呢?因为正则的匹配是从字符串的最左边开始匹配,只要有一个符合匹配模式的就停止匹配。
分组和引用
上面我们说过,在正则表达式中小括号是有特殊含义的,如果真的想要匹配带有小括号的字符串,必须要用反斜杠转移,接下来我们就来介绍一下 ()
小括号的几种作用。
1. 作用一:把匹配模式中的部分项组合成子表达式
类似于这样 /java(script)?/
,这种匹配模式的意思就是,匹配一段为 java
或者 javascript
的字符串。我们可以试一下,如果去掉这个括号会是什么结果,即 /javascript?/
,这种匹配模式的意思就是,匹配一段为 javascrip
或者 javascript
的字符串。
所以我们可以很清楚的知道,()
小括号可以帮我们组合一个子表达式,然后将这个子表达式作为整体,配合 |
、*
、?
、+
等符号去处理。
2. 作用二:定义一个子匹配模式,方便获取子匹配模式匹配到的字符串
在将这个作用前,我还是再来详细介绍一下我之前例子中用到的匹配方法 match()
的具体用法。
match() 方法需要传入一个正则表达式,然后根据这个参数去匹配字符串,最后返回一个数组,数组的第一个元素是该参数匹配到的字符串,数组的第二个元素是该正则表达式中第一个()
小括号内匹配到的字符串,数组的第三个元素是该正则表达式中第二个()
小括号内匹配到的字符串,这样以此类推。若没匹配到就返回null
介绍完 match() 方法的使用以后,我们来看一个例子
/*---------------------在匹配模式中加小括号--------------*/let pattern = /java(script\d+)/let str = "javascript2333"str.match(pattern) //返回 ['javascript2333', 'script2333']/*---------------------不在匹配模式中加小括号--------------*/let pattern = /javascript\d+/let str = "javascript2333"str.match(pattern) //返回 ['javascript2333']
我们可以看到,在匹配模式中加了小括号,最后返回的数组中会额外返回一个元素,用于存放小括号定义的子匹配模式匹配到的字符串。
接下来举一个实战中的例子
有这样一个 url 地址 https://www.baidu.com/s?query=javascript
,我们知道 ?
后面跟的是请求参数,如果我们想要获取请求参数 query 的值,也就是 query=
后面的字符串,我们该如何使用正则表达式去匹配呢?
let pattern = /query=([a-zA-Z]+)/let str = "https://www.baidu.com/s?query=javascript"str.match(pattern) //返回 ['query=javascript', 'javascript']
在这个例子中,我们很明确的知道我们只是想获取 query=
后面的字符串,但是如果我们直接用这个模式 /query=[a-zA-Z]+/
去匹配的话,我们最后只能获得 query=javascript
这样一整段字符串。所以我们可以在我们可以使用小括号来定义一个子匹配模式,这样在返回的数组中直接获取小括号匹配返回的值就可以了。
3. 作用三:小括号定义的子匹配模式可以被反斜杠+数字再次引用
其实作用三是在作用二的基础上的,我们可以通过一个反斜杠 \
加上数字 n来引用该匹配模式中第n个括号定义的子匹配模式,例如 /java(script)\1/
,这个意思就是 \1
的部分需要匹配的字符串要跟(script)
一样
let pattern = /java(\d+)\1/let str = "java123123"str.match(pattern) //返回 ['java123123', '123']
在这个例子中,\1
对(\d+)
进行了一次引用,注意是引用,而不是这样 /java(\d+)(\d+)/
。我们来看一下这两者的区别
/*----------------使用反斜杠加数字引用----------------*/let pattern = /java(\d+)\1/let str = "java123321"str.match(pattern) //返回 null/*----------------完全的重复一遍子匹配模式----------------*/let pattern = /java(\d+)(\d+)/let str = "java123321"str.match(pattern) //返回 ['java123321', '12332', '1']
通过这两个例子的对比,我们可以发现以下几点区别:
子匹配模式
必须和反斜杠+数字
匹配到的字符串一模一样,否则匹配失败两个相同的子匹配模式则不需要两者匹配到一模一样的字符串
反斜杠+数字
虽然是对定义的子匹配模式的引用,但在匹配返回的结果里,却不会返回反斜杠+数字
匹配到的内容
补充:如果我们用小括号定义的子匹配模式不想被反斜杠+数字
引用,我们可以在小括号内部的最前面加上 ?:
,即这种形式 (?:\d+)
,这样的话我们就无法在后面使用 反斜杠+数字
来引用这个子匹配模式了。
例如:
let pattern = /java(?:script)(\d+)\1/let str = "javascript1212"str.match(pattern) //返回 ['javascript1212', '12']
例子中我们可以看到, \1
是对第二个子匹配模式(\d+)
进行了引用,其实我们可以这样理解,使用这种形式(?:...)
定义的子匹配模式,不会被计入编号中,所以也不会被 反斜杠+数字
引用。
结束语
第二篇对于 JavaScript正则表达式的讲解就先到这里,明天后天会继续更新第三篇,并且我会在之后的文章上放上前几篇的文章链接,方便大家观看,希望大家持续关注,点个关注,不迷路