正则在前端的世界里是多么重要,业务离不开它,二次封装离不开它,工具库也离不开它。想要提高自己的开发效率,那就马上拿下它!

正则元字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
\ 转义字符
^ 以……开头
$ 以……结尾
\n 换行符
. 任意字符
() 分组
x|y x或y
[xyz] x或y 或z
[^xyz] 除了xyz三个中的任意字符
[a-z] a-z之间的任意字符
[^a-z] 除了a-z之间的任意字符

\d 0-9之间的数字 \D 除了0-9之间以外的数字
\b 一个边界符
\w 数字、字母、下划线任意字符,等价于[0-9a-zA-Z_]
\s 一个空白字符(空格、制表符、换页符……

* 出现零到多次
+ 出现一到多次
? 出现零或一次
{n} 出现n次
{n,} 出现n到多次
{n,m} 出现n到m次

注意事项
中括号[]

  1. 在中括号[]中,出现的所有字符都是代表字符本身,不需要转义
  2. 中括号[]中不识别两位数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 验证有效数字
// 1、开头+、-可有可无
// 2、一位数0-9均可,多位数不能以0开头
// 3、小数点要么出现,后面必须带数字,要么不出现
const validNumberReg = /^[+-]?(\d|([1-9]\d))(\.\d+)?$/

// 验证年龄18-65之间
const validAgeReg = /^(1[8-9]|[2-5]\d|6[0-5])$/

// 验证邮箱
// 1、@左边:数字、字母、下划线、点.、中杠-
// 2、@右侧 带点.+字母(可出现一次或多次),如.com .cn .com.cn
const emailReg = /^[\w.-]+@[0-9a-zA-Z]+(\.[a-zA-Z]{2,4}){1,2}$/

// 验证身份证号
const idReg = /^\d{17}(\d|X)$/
// 得到详细信息,使用正则捕获即可
const detailIdReg = /^(\d{2})(\d{4})(\d{4})(\d{2})(\d{2})(\d{2})(\d)(\d|X)$/

正则懒惰性:每次lastIndex都为0,永远只捕获第一个数字,而不是全部匹配结果。

解决懒惰性:加g,循环捕获即可,lastIndex会一直改变。

1
2
3
4
5
6
7
8
9
10
11
12
const reg = /\d+/
const str = 'sddefer333dvdfv12de45'
console.log(reg.exec(str)); //[ '333', index: 7, input: 'sddefer333dvdfv12', groups: undefined ]
// 解决懒惰性,加g,循环捕获即可,lastIndex会一直改变
const reg0 = /\d+/g
let arr = []
let res = reg0.exec(str)
while (res) {
arr.push(res[0])
res = reg0.exec(str)
}
console.log(arr); //[ '333', '12', '45' ]

正则贪婪性:每次捕获都是按照匹配最长的结果捕获的。

解决贪婪性:只需加?即可,取消正则捕获贪婪性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 正则贪婪性,每次捕获都是按照匹配最长的结果捕获的
const reg1 = /\d+/g
console.log(reg1.exec(str)); //不想得到333,只想得到3如何解决?
// 解决贪婪性,只需加?即可,取消正则捕获贪婪性
const reg2 = /\d+?/g
console.log(reg2.exec(str));
// 得到全部单个数字
let arr1 = []
let res1 = reg2.exec(str)
while (res1) {
arr1.push(res1[0])
res1 = reg2.exec(str)
}
console.log(arr1); //[ '3', '3', '3', '1', '2', '4', '5' ]

match方法

虽然在当前情况下match比exec更加简洁好用,但是match也存在一些局限性
在分组捕获的情况下, match只能捕获到大正则匹配的内容,而无法捕获小正则捕获的内容

1
2
3
4
5
6
7
8
9
10
const r1 = /\d+?/g
const r2 = /\d+/g
const r3 = /\d+/
console.log(str.match(r1)); //[ '3', '3', '3', '1', '2', '4', '5' ]
console.log(str.match(r2)); //[ '333', '12', '45' ]
console.log(str.match(r3));
//[ '333',
// index: 7,
// input: 'sddefer333dvdfv12de45',
// groups: undefined ]

分组捕获

  1. 改变默认的优先级
  2. 分组引用:\1代表和第一个分组出现一模一样的内容,\2代表和第二个分组出现一模一样的内容
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    const gReg0 = /^(\w)\1(\w)\2$/
    console.log(gReg0.test('yypp'));
    // 3、分组捕获,正则捕获的时候,不仅仅把大正则匹配的内容捕获到,也能把小正则匹配的内容捕获到
    const gReg1 = /^(\d{2})(\d{4})(\d{4})(\d{2})(\d{2})(\d{2})(\d)(\d|X)$/
    const id = '422201199612120401'
    console.log(gReg1.exec(id));
    // ["422201199612120401", "42", "2201", "1996", "12", "12", "04", "0", "1", index: 0, input: "422201199612120401", groups: undefined]
    // arr[0] 大正则匹配
    // arr[1] 第一个分组匹配
    // arr[2] 第二个分组匹配
    // ……
    // 如果需要不捕获其中某个分组匹配的内容,添加?:即可
    const gReg2 = /^(\d{2})(\d{4})(\d{4})(\d{2})(\d{2})(?:\d{2})(\d)(?:\d|X)$/
    console.log(gReg2.exec(id));
    // ["422201199612120401", "42", "2201", "1996", "12", "12", "0", index: 0, input: "422201199612120401", groups: undefined]
    console.log(id.match(gReg2)); // 和exec获取的结果是一样的

exec与match区别

1
2
3
4
5
6
7
8
9
10
11
12
13
const dReg = /yyyppp(\d+)/g
const yp = 'yyyppp1234yyyppp5566yyyppp8899'
// 我们用exec执行三次,每一次不仅仅把大正则匹配的内容获取到,而且还可以获取第一个正则获取的内容
console.log(dReg.exec(yp));
//  ["yyyppp1234", "1234", index: 0, input: "yyyppp1234yyyppp5566yyyppp8899", groups: undefined]
console.log(dReg.exec(yp));
// ["yyyppp5566", "5566", index: 10, input: "yyyppp1234yyyppp5566yyyppp8899", groups: undefined]
console.log(dReg.exec(yp));
// ["yyyppp8899", "8899", index: 20, input: "yyyppp1234yyyppp5566yyyppp8899", groups: undefined]

// 而match只能捕获大正则匹配的内容
console.log(yp.match(dReg));
// [ 'yyyppp1234', 'yyyppp5566', 'yyyppp8899' ]

正则的捕获:正则的exec方法、字符串的match方法、字符串的replace方法

1
2
3
4
// replace方法
const ypRes = yp.replace('yyyppp', 'yp').replace('yyyppp', 'yp').replace('yyyppp', 'yp')
console.log(ypRes); //yp1234yp5566yp8899
console.log(yp.replace(/yyyppp/g, 'yp')); //yp1234yp5566yp8899

应用1:将数字替换为文字

1
2
3
4
5
6
let oldStr = '243545'
let numArr = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十']
oldStr = oldStr.replace(/\d/g, function() {
return numArr[arguments[0]]
})
console.log(oldStr);

应用2:获取字符串中出现次数最多的字符,并且获取出现的次数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const randomStr = 'sfdcjdfvsjhvvbshbbbbljcsdkdsfchieorl'
let obj = {}
randomStr.replace(/[a-z]/gi, function() {
const val = arguments[0]
obj[val] >= 1 ? obj[val]++ : obj[val] = 1
})
//获取最多出现的次数
let maxNum = 0
for (let key in obj) {
obj[key] > maxNum ? maxNum = obj[key] : null
}
// 把所有复合出现maxNum的数字找出来
let maxArr = []
for (let key in obj) {
obj[key] === maxNum ? maxArr.push(key) : null
}
console.log(maxArr);

应用3:模板引擎实现原理

1
2
3
4
5
6
let tplStr = 'My name is {0}, my age is {1}, I love {2}.'
const data = ['yp', '23', 'singing']
tplStr = tplStr.replace(/{(\d+)}/g, function() {
return data[arguments[1]] //arguments[0]是匹配的内容,arguments[1]是匹配的索引
})
console.log(tplStr);

应用4:获取url中的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
const url = 'http://www.yp.com/movie?name=yp&age=12&hobby=singing'
const urlReg = /([^?&=]+)=([^?&=]+)/g
const params = {}
// let ret = urlReg.exec(url)
// while (ret) {
// params[ret[1]] = ret[2]
// ret = urlReg.exec(url)
// }
// console.log(params); //{ name: 'yp', age: '12', hobby: 'singing' }
url.replace(urlReg, function() {
params[arguments[1]] = arguments[2]
})
console.log(params); //{ name: 'yp', age: '12', hobby: 'singing' }

应用5:时间格式化 —— 将”2015-6-10 9:12:00”变为”2015年6月10日 9时12分00秒”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
let oldTime = '2015-6-10 9:12:00'
const timeReg = /{(\d+)}/g
// 先获取timeArr
const preReg = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2})$/g
let timeArr = []
oldTime.replace(preReg, function() {
timeArr = [].slice.call(arguments)
timeArr = timeArr.slice(1, 7)
})
console.log(timeArr) //[ '2015', '6', '10', '9', '12', '00' ]
// 设定好目标时间格式,直接进行正则替换
let formatTime = '{0}年{1}月{2}日 {3}时{4}分{5}秒'
formatTime = formatTime.replace(timeReg, function() {
return timeArr[arguments[1]]
})
console.log(formatTime) //2015年6月10日 9时12分00秒