JavaScript正则表达式的模式匹配教程,而且附带充足的实战代码

引言

其实我写这篇文章的话,主要是想本身从新复习一遍正则表达式。咱们也知道正则表达式在不少语言中都是通用的,因此学好这个好处不少。接下来,就跟我一块儿来学习一下正则表达式,从0到入门吧。javascript

正文

1、正则表达式定义

正则表达式(regular expression)是一个描述字符模式的对象,简单点来说就是经过正则表达式规定的模式,从一堆字符串中,找到与该模式匹配的字符串,并能够完成检索或字符串替换的功能。java

来举个例子,让你们更形象地理解正则表达式的做用。python

你去买苹果,老板给你随便拿了几个,但你以为他给你挑的苹果很差,因而你想从中拿掉一些很差的苹果,再去挑一些好的苹果,在选以前,你先想好本身挑选苹果的标准,好比苹果的纹路要多 、苹果要很红 、苹果不能太大等等,而后再根据你本身定的标准去这么多苹果里挑选到彻底符合你标准的苹果放进本身的袋子里,或者是替换掉袋子里你以为很差的苹果。web

但愿大家能对正则表达式有个初步的印象。正则表达式

2、正则表达式的使用

在JavaScript中,正则表达式用RegExp对象表示,咱们能够经过两种方式建立一个正则表达式对象:express

  1. RegExp直接量
  2. new RegExp()

3、RegExp直接量

let pattern = /javascript/ 这样双正斜杠包裹一个匹配模式的写法就是RegExp直接量,这种方法实际上是new RegExp()的一种能语法糖的写法。这一部分咱们都用RegExp直接量的方法来说解,在后面咱们会介绍 new RegExp() 的用法数组

(1)正则表达式初体验

接下来看一个例子,来初次体验一下正则表达式的使用并发

//RegExp直接量 建立一个字符串的匹配标准
let pattern = /javascript/           
let str = "I love javascript"

str.search(pattern)           //返回 7

我来说一下这段代码,首先咱们经过两个正斜杠// 建立了一个正则表达式对象,而后将咱们要匹配的字符串放到这两个斜杠中,咱们例子中就是将javascript放到两个斜杠中,意思就是咱们的匹配标准就是:要匹配到javascript这段字符串。而后咱们调用了一个检索的方法search(),这个方法须要传入一个正则表达式对象为参数,根据这个参数去字符串中匹配相应的字符串,若是匹配到了,则返回第一个与之匹配的字符的索引值;若没匹配到,返回-1。例子中,变量str中有一段字符串为javascript,因此匹配成功,并返回javascript的开头字母的索引值,为7svg

(2)深刻了解正则

刚才咱们体验了一下最简单的正则表达式去匹配字符串。在上一个例子中,咱们将javascript做为标准去匹配,其实大多数的字符都是按照字面含义去匹配的,意思就是你输入什么字符,就去匹配什么字符,好比/python/ 就是去字符串中匹配 python字符串 、/123/ 就是去匹配 123 字符串函数

可是在正则表达式中,\ 反斜杠有特殊的做用,在一些字符前面加一个反斜杠,能起到转义的做用。例如 /n/ 是匹配字符串 n 的,可是/\n/中,n的前面加了一个反斜杠,就将其转义了,这个匹配模式的意思就是去匹配换行符,下面列出一些其余的转义字符

字符 匹配
字母和数字字符 自身
\o NUL 字符(\u0000)
\t 制表符(\u0009)
\n 换行符(\u000A)
\v 垂直制表符(\u000B)
\f 换页符(\u000C)
\r 回车符(\u000D)

在正则表达式中,许多标点符号都具备特殊的含义,它们是:^ $ . * + ? = ! : | \ / ( ) [ ] { } ,当咱们想要匹配这些字符时,也须要在它们前面加上反斜杠 \ ,例如

/*--------------不对小括号进行转义----------------*/
let pattern = /you(kimy)/
let str = "I love you(kimy)"

str.search(pattern)       //返回 -1 表示未匹配到相应字符

/*--------------对小括号进行转义-----------------*/
let pattern = /you\(kimy\)/
let str = "I love you(kimy)"

str.search(pattern)       //返回 7 表示匹配成功

为何这些标点字符须要进行特殊的转义呢?由于它们有别的用处,咱们接下来会慢慢介绍他们的用处

字符类

将直接量字符单独放在方括号里就组成了一个字符类,一个字符类能够匹配它所包含的任意字符。例如/[abcd]/ 就是匹配到 abcd四个字符中的任意一个即为匹配成功。若是在方括号里最前面加上一个 ^ 符号,则表示为,只要匹配到一个不是方括号里的字符的字符串即为匹配成功,例如 /[^abc]/就是匹配到不是 abc 三个字符中的任意一个即为匹配成功。 字符类还可使用 - 来表示字符的一个范围,例如 /[a-zA-Z0-9]/表示匹配到任意一个大小写字母或者数字都为匹配成功。

在正则表达式中,还给出了一些特殊字符的转义,咱们来看下列的表格

字符 匹配
[…] 方括号内的任意一个字符
[^…] 不在方括号内的任意一个字符
. 除了换行符和其余Unicode行终止符以外的任意字符
\w 至关于[a-zA-Z0-9]
\W 至关于[^a-zA-Z0-9]
\s 任何Unicode空白符
\S 任何非Unicode空白符
\d 任何数字,至关于[0-9]
\D 任何非数字,至关于[^0-9]
[\b] 退格直接量

咱们来选取表格中的 \d 来举个例子

let pattern = /python\d/
let str = "I love python3"

str.search(pattern)   //返回 7

咱们设置的匹配模式是 /python\d/,表示匹配到一个字符串为python而且后面紧跟一个任意数字便可,因此成功匹配到 str 中的python3字符串

重复

在上一部分,咱们知道字符类都是匹配一个字符,例如 /\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 的字符串。

因此咱们能够很清楚的知道,() 小括号能够帮咱们组合一个子表达式,而后将这个子表达式做为总体,配合 |*?+ 等符号去处理。

  1. 做用二:定义一个子匹配模式,方便获取子匹配模式匹配到的字符串

在将这个做用前,我仍是再来详细介绍一下我以前例子中用到的匹配方法 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 这样一整段字符串。因此咱们能够在咱们可使用小括号来定义一个子匹配模式,这样在返回的数组中直接获取小括号匹配返回的值就能够了。

  1. 做用三:小括号定义的子匹配模式能够被反斜杠+数字再次引用

其实做用三是在做用二的基础上的,咱们能够经过一个反斜杠 \ 加上数字 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']

经过这两个例子的对比,咱们能够发现如下几点区别:

  1. 子匹配模式必须和反斜杠+数字 匹配到的字符串如出一辙,不然匹配失败
  2. 两个相同的子匹配模式则不须要二者匹配到如出一辙的字符串
  3. 反斜杠+数字 虽然是对定义的子匹配模式的引用,但在匹配返回的结果里,却不会返回 反斜杠+数字 匹配到的内容

补充:若是咱们用小括号定义的子匹配模式不想被反斜杠+数字引用,咱们能够在小括号内部的最前面加上 ?:,即这种形式 (?:\d+) ,这样的话咱们就没法在后面使用 反斜杠+数字 来引用这个子匹配模式了。

例如:

let pattern = /java(?:script)(\d+)\1/
let str = "javascript1212"

str.match(pattern)      //返回 ['javascript1212', '12']

例子中咱们能够看到, \1 是对第二个子匹配模式(\d+)进行了引用,其实咱们能够这样理解,使用这种形式(?:...)定义的子匹配模式,不会被计入编号中,因此也不会被 反斜杠+数字 引用。

指定匹配位置

在正则表达式中,我能够利用某些字符,去指定匹配发生的位置。这些字符咱们称之为正则表达式的

字符 含义
^ 匹配字符串的开头
$ 匹配字符串的结尾
\b 匹配一个单词的边界
\B 匹配非单词边界的位置
(?=p) 零宽正向先行断言,?=后面的字符都要与p匹配,但不能包括p的那些字符
(?!p) 零宽负向先行断言,?!后面的字符不与p匹配

咱们来逐个说一下这几个字符的用法:

  • ^ 符号

^ 这个符号是将匹配位置定位到字符串的开头,直接来看一个例子

/*--------------------------第一种状况--------------------*/

let pattern = /^javascript/
let str = "javascript is fun"

str.match(pattern)         //返回 ['javascript']

/*--------------------------第二种状况--------------------*/

let pattern = /^javascript/
let str = "i love javascript"

str.match(pattern)         //返回 null

咱们匹配的模式是,要以javascript开头的字符串。第一种状况,字符串以 javascript开头,因此能匹配到;第二种状况,javascript不是在开头的位置,而是在末尾的位置,不符合匹配模式,因此匹配失败返回null。

在前面咱们有一个地方还用到了 ^ 这个符号,那就是 [^abc] ,因此必定要注意,当 ^ 放在方括号里,表示的是取反,也就是说不匹配方括号里的任何字符。

  • $ 符号

$ 这个符号是将匹配位置定位到字符串的末尾,直接来看一个例子

/*--------------------------第一种状况--------------------*/

let pattern = /javascript$/
let str = "javascript is fun"

str.match(pattern)         //返回 null

/*--------------------------第二种状况--------------------*/

let pattern = /javascript$/
let str = "i love javascript"

str.match(pattern)         //返回 ['javascript']

咱们的匹配模式是,字符串要以javascript结尾。第一种状况,字符串结尾处字符是 fun ,不符合匹配模式,返回null;第二种状况,结尾处字符为javascript,符合匹配模式,因此匹配成功。

咱们能够看一下若是 ^ 符号 和 $ 符号一块儿使用是什么状况:

let pattern = /^javascript$/
let str = "javascript"

str.match(pattern)      //返回 ["javascript"]

当这两个符号一块儿使用时,匹配模式就变成了匹配整段字符串,而且字符串的内容就是 ^ 与 $ 之间的内容

  • \b

这个符号的做用是匹配一个单词的边界,咱们来看几个例子来理解一下

/*-------------------------第一种状况----------------------*/

let pattern = /\bjava/
let str = "I love javascript"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第二种状况----------------------*/

let pattern = /\bjava/
let str = "javascript is fun"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第三种状况----------------------*/

let pattern = /\bjava/
let str = "1javascript is fun"

str.match(pattern)         // 返回 null 匹配失败

/*-------------------------第四种状况----------------------*/

let pattern = /java\b/
let str = "I am learning java"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第五种状况----------------------*/

let pattern = /java\b/
let str = "I am learning javascript"

str.match(pattern)         // 返回 null 匹配失败

/*-------------------------第六种状况----------------------*/

let pattern = /\bjava\b/
let str = "I think java is fun"

str.match(pattern)         // 返回 ['java'] 匹配成功

看了上面几个例子,你有没有得出什么规律?

其实 \b 的做用就是将匹配的点放到一个字符串前面(\b放前面)或后面(\b放后面)的 [^a-zA-Z0-9] 处,也能够理解为 \b 能够替换那些特殊字符,但 \b 不会做为匹配的内容。

  • \B

\B 则与 \b 相反了, \b 能够替换那些特殊字符,那么\B就是用来替换那些非特殊字符,也就是 [a-zA-Z0-9] 内的字符。

也来举几个简单的例子吧

/*-------------------------第一种状况----------------------*/

let pattern = /java\B/
let str = "I love javascript"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第二种状况----------------------*/

let pattern = /java\B/
let str = "I love java"

str.match(pattern)         // 返回 null 匹配失败


/*-------------------------第三种状况----------------------*/

let pattern = /\Bjava\B/
let str = "I love 1javascript"

str.match(pattern)         // 返回 ['java'] 匹配成功

/*-------------------------第四种状况----------------------*/

let pattern = /\Bjava\B/
let str = "I love javascript"

str.match(pattern)         // 返回 null 匹配失败
  • (?=p)

(?=p)表示接下来的字符要与p匹配,但p不会做为内容返回

先来看一个例子

let pattern = /java(script)?(?=\:)/
let str = "java: my favorite language"

str.match(pattern)       //返回 ["java", undefined] 匹配成功

该例子的匹配模式:匹配一段字符串为java 而后 script 能够有一个也能够没有,后面必须跟一个 :,才能匹配成功,返回匹配内容,可是匹配内容中不包含 :

再来看一个相似的例子

let pattern = /java(script)?(?=\:)/
let str = "javascript is my favorite language"

str.match(pattern)       //返回 null 匹配失败

该例子匹配失败是由于字符串中的javascript后面没有 :,没有知足 (?=\:)的匹配要求

  • (?!p)

(?!p)与(?=p)相反,它表示接下来的字符不与p匹配

咱们也来看一个例子

let pattern = /java(?!script)/
let str = "javascript is my favorite language"

str.match(pattern)       //返回 null 匹配失败

该例子的匹配模式是:匹配一段字符,只要java后面紧跟这的字符不是script即为匹配成功,同时java后面跟的内容也不会做为内容返回。但这个例子中的 str 里, java后面紧跟着的就是script,因此匹配失败。那么成功的例子就是这样的

let pattern = /java(?!script)/
let str = "javascr1111 is my favorite language"

str.match(pattern)       //返回 ["java"] 匹配成功

在该例子中, java 后面跟着的就不是script了,因此匹配成功了。java后面的字符不做为内容返回,因此最后的匹配结果就是 java

修饰符

正则表达式的修饰符是用以说明高级匹配模式的规则,而且修饰符是放在// 双斜杠外面的,例如这样 /java/g,g就是修饰符

接下来给出一张表,列出了修饰符的种类和含义

字符 含义
i 执行不区分大小写的匹配
g 执行全局匹配,即找到全部匹配的项并返回,而不是找到第一个以后就中止
m 多行匹配模式

咱们来逐个讲解它们各自的用途:

  • 字符 i

咱们以前会用这样的匹配模式去匹配 /[Jj]ava[Ss]cript/,这是由于咱们不知道字符串中写的是 javascript 仍是 JavaScript。其实咱们能够直接用一个修饰符 i 来避免大小写的干扰,就想这样 /javascript/i

let pattern = /javascript/i
let str = "JavaScript"

str.match(pattern)        // 返回 ['JavaScript'] 匹配成功

咱们能够看到,匹配时忽略了大小写的影响,仍然匹配成功了

  • 字符 g

咱们以前匹配字符串时,都是匹配到第一个就结束匹配返回内容,例如

let pattern = /java/
let str = "I love javascript and java"

str.match(pattern)      //返回 ["java"] 匹配到javascript的java就返回了

咱们能够看到 str 字符串中,有两个java,但只匹配到javascript就返回了,若是咱们要匹配到字符串中全部符合匹配模式的字符串,咱们就能够用修饰符g,就像这样 /java/g

let pattern = /java/g
let str = "I love javascript and java"

str.match(pattern)    //返回 ["java", "java"] 匹配到了全部的java
  • 字符 m

若是一个字符串中包含换行符,则该字符串就有多行。这时咱们可使用修饰符 m 进行多行模式的匹配。

let pattern = /java$/m
let str = "java\nis fun"

str.match(pattern)            //返回 ['java'] 匹配成功

在这个例子中,str内有一个换行符,这样的话,第一行就是 java ,第二行就是 is fun 。咱们的匹配模式是查找每一行,只要这一行的结尾是java,就返回匹配到的内容。

其实在这个例子中,咱们看到,使用了修饰符 m 之后,锚字符 ^ 和 $ 再也不是以一整个字符串的开头或结尾为匹配点了,而是以每一行的开头或结尾为匹配点。

(3)用于模式匹配字符串的方法

咱们在前面的不少例子中用到了search()方法 、match()方法,他们都是匹配字符串的方法,其实还有不少种匹配的方法,他们的用法和做用各不相同,咱们来了解一下

用于模式匹配字符串的方法有如下几种:

  1. search( )
  2. replace( )
  3. match( )
  4. split()

接下来咱们来详细讲解一下

search()

该方法须要传入一个正则表达式做为参数,并返回第一个与之匹配的字符串的起始位置,若没匹配到,则返回-1

"javascript".search(/script/)      //返回 4

"javascript".search(/sccc/)        //返回-1

replace()

该方法是用于字符串的检索与替换。须要传入两个参数,第一个参数为正则表达式;第二个参数为须要进行替换的字符串。匹配成功则会用第二个参数去替换匹配到的字符串,并返回替换后的总体字符串;若没匹配成功,则返回原来的总体字符串。

"javascript".replace(/java/, 'python')  //返回 pythonscript

"javascript".replace(/abc/, 'python')   //返回 javascript

若使用了修饰符g,则会将全部匹配到的字符串都进行一个替换。

"javascript and java".replace(/java/, 'python')  //返回 pythonscript and java

"javascript".replace(/java/g, 'python')   //返回 pythonscript and python

match()

该方法须要传入一个正则表达式做为参数,返回一个由匹配结果组成的数组,若是正则表达式使用了修饰符g,则将全部匹配到的结果都放到数组中并返回。

"javascript and java".match(/java/)   //返回 ['java']

"javascript and java".match(/java/g)   //返回 ['java', 'java']

补充:当match()传入一个非全局的正则表达式时,实际上返回的数组里有两个属性:index和input,他们分别表示匹配到的字符串的起始位置和检索的整个字符串。

let ret = "I love javascript and java".match(/java/)
ret.index        //返回 7
ret.input        //返回 I love javascript and java

split()

该方法是用于将字符串分割,并将分割开的部分做为数组中的元素,最终返回一个数组。该方法须要传入一个正则表达式做为参数,去肯定须要根据什么去分割这串字符串,若匹配成功,最终返回一个数组,数组中的元素就是每一个被分割的字符串;若匹配失败,也会返回一个数组,数组中只有一个元素,那就是这个字符串总体。

'1,2,3,4,5,6'.split(/,/)   //返回 ['1', '2', '3', '4', '5', '6']

'1,2,3,4,5,6'.split(/\+/)  //返回 ['1,2,3,4,5,6']

4、new RegExp()

在第三部分讲解正则表达式时,咱们都是用的直接量的形式建立的RegExp对象,其实使用直接量,在内部仍是会调用RegExp()构造函数去建立对象实例的,那咱们就来看看直接经过RexExp()构造函数是如何建立对象的吧。

RegExp()构造函数一共有两个参数,第一个参数为正则表达式的主体部分;第二个参数是可选的,为修饰符。须要注意的是,咱们在写主体部分的时候,有些地方要用一个反斜杠\进行转义,咱们必须将一个反斜杠\ 替换成两个反斜杠 \\。接下来咱们来看一下一个简单的例子:

//建立一个RegExp对象,全局匹配字符串中连着的三个数字
let pattern = new RegExp("\\d{3}", "g")

这种建立RegExp对象的方法有一个好处,就是能够动态的改变正则表达式的主体部分;而RegExp直接量就没法作到动态变化。

RegExp对象的属性

咱们建立的每一个RegExp对象(包括RegExp直接量)都包含有5个属性:

  1. source:这是一个只读属性,包含正则表达式的文本,例如 /java/的source表示的就是 java
  2. global:这是一个只读的布尔值,用以表示这个正则表达式是否使用了修饰符 g
  3. ignoreCase:这是一个只读的布尔值,用以表示这个正则表达式是否使用了修饰符 i
  4. multiline:这是一个只读的布尔值,用以表示这个正则表达式是否使用了修饰符 m
  5. lastIndex:这是一个可读写的整数值,若是匹配模式中有修饰符 g,则这个属性会存储下一次检索的开始位置,这个属性只有在调用exec()和test()两个方法的时候会用到。

RegExp对象的方法

RegExp对象定义了两个用于匹配的方法——exec()test(),这两个方法与咱们以前讲到的用于模式匹配字符串的方法不一样的是,前者是定义在RegExp对象上的方法,而且传入的参数是字符串;然后者是调用字符串的方法,传入的参数是RegExp对象。

  • exec()

该方法就跟前面说到的不传入修饰符g的matach()方法同样,它对字符串执行一个正则表达式,若是匹配失败,返回null;若是匹配成功,则返回一个数组,数组的第一个元素是正则表达式匹配到的字符串,剩下的元素则是子表达式匹配到的字符串,同时该数组也包含indexinput两个属性。

来看一个例子,体会一下exec()方法的做用

let pattern = new RegExp("java", "g")
let ret = pattern.exec("I love javascript and java")  //返回["java"]

ret.index     //返回 7
ret.input     //返回 I love javascript and java

exec()match() 方法不一样的是,无论正则表达式是否使用修饰符g,exec()都只会将第一个匹配到的字符串以及子表达式匹配到的字符串放到数组里返回;而match()方法在没有使用修饰符g时,跟exec()同样,若是使用了修饰符g,则将全部匹配到的字符串都放在数组里一块儿返回,而且不会返回圆括号里匹配到的字符串,同时,该数组里不包含indexinput两个属性。

那么这里引起一个疑问,既然无论是否使用修饰符g,exec()方法都只会返回第一个匹配到的字符串,那这个修饰符g有什么用呢? 其实咱们在前面有说到,RegExp对象内有一个属性叫作 lastIndex,该属性默认为0。当咱们调用exec()方法,而且使用了修饰符g进行匹配时,若匹配成功,lastIndex将变为下一次检索开始位置的索引值;若匹配失败,lastIndex则重置为0

let pattern = new RegExp("java", "g")
console.log(pattern.lastIndex)        //查看lastIndex默认为0
let str = "I love javascript and java"

pattern.exec(str)               //进行第一次检索匹配,返回["java"]
console.log(pattern.lastIndex)  //此时lastIndex为 4

pattern.exec(str)               //进行第二次检索匹配,返回["java"]
console.log(pattern.lastIndex)  //此时lastIndex为 19

pattern.exec(str)               //进行第三次检索匹配,返回null
console.log(pattern.lastIndex)  //此时lastIndex为 0

从上面这个例子咱们能看看到,lastIndex默认为0,表示从字符串的开头开始检索,当咱们进行第一次检索时,匹配到了javascript中的java,返回了该字符串,这时lastIndex变为第一次匹配到的字符串的起始位置索引 4;咱们进行第二次索引,是从索引 5 开始匹配的,日后检索到字符串末尾的java,并返回该字符串,同时lastIndex变为第二次匹配到的字符串起始位置索引 19;咱们进行第三次索引,是从索引 20 开始匹配的,日后匹配,已经没法匹配到对应的字符串了,因此返回一个null,并将lastIndex重置为0,表示下一次检索又从字符串的开头开始检索。

  • test()

该方法与exec()相似,该方法也是传入一个字符串做为参数,对该字符串进行检索,若是匹配到了相应的字符串,则返回true;若是没匹配到,则返回false。

let pattern = new RegExp("java", "g")
let ret = pattern.test("I love javascript and java")  //返回 true

test() 与 exec() 相同的是,若是匹配时使用了修饰符g,test()也会根据对象内部属性 lastIndex 进行检索匹配,这里就很少作说明了。

5、实战应用

(1)判断电话号码格式

应用场景:判断用户输入的电话号码格式是否正确
电话号码格式:1开头,后面跟10位数字

let str = "12356456132"  //str为用户输入的电话号码
let re = /^1\d{10}$/     
if(re.test(str) !== true) {
	console.log('电话号码格式不正确')
}
else {
	console.log('电话号码格式正确')
}

(2)判断邮箱格式

应用场景:判断用户输入的邮箱格式是否正确
邮箱格式:第一部分@第二部分,第一部分由字母、数字 和 短横线 - 组成,第二部分由(字母、数字、短横线 - ).cn.com…… 组成

let str = "561325647@qq.com"    //用户输入的邮箱
let re = /^[\w-\.]+@(\w-?)+(\.\w{2,})+$/
if(re.test(str) !== true) {
	console.log('邮箱格式不正确')
}
else {
	console.log('邮箱格式正确')
}

(3)判断昵称格式

应用场景:判断用户输入的昵称是否符合规定格式
昵称格式:昵称由字母、数字、下划线组成,必须由字母开头,长度为4-16位

let str = "Lpyexplore233"     //用户输入的昵称
let re = /^[a-zA-Z][\w_]{3,15}$/
if(re.test(str) !== true) {
	console.log('昵称格式不正确')
}
else {
	console.log('昵称格式正确')
}

结束语

花了两天的事件,本身从新完完整整地复习了一边正则表达式,而且将知识点以博客的形式展示了出来,但愿这篇文章能对你们有所帮助吧。喜欢的关注我,之后还会根据JavaScript不一样部分的知识点进行整理并发表博客~