1) 正则创建的两种形式
var reg1 = /1/; //字面量形式 把内容写到双斜杆(//)里面
var reg2 = new RegExp('1');//构造函数
reg1.test("123");//true
reg2.test("123");//true
2) 特殊元字符:
| 符号 | 含义 |
|---|---|
| \d | 数字 |
| \D | 除了数字以外的其他字符 |
| \w | 数字、字母或者下划线"_" |
| \W | 除(数字、字母或者下划线"_")其他字符 |
| 以什么开头,用在正则开头 | |
| $ | 以什么结尾,用在正则最后 |
| [abc] | a或者b或者c |
| [^ab] | 除ab以外其他的字符 |
| [a-z] | 小写字母 |
| [A-Z] | 小写字母 |
| [a-zA-Z] | 所有字母 |
| a|b|c | a或者b或者c |
| . | 除了换行符以外其他的字符,若再[]里面就代表"."字符串 |
| ( ) | 提升优先级 |
| /^11|12$/ | 以11开头或者以12结尾的字符串 |
| /^(11|12)$/ | 要不11 要不12 |
3) 量(数量)词元素,用在修饰的字符后面
| 元素 | 含义 |
|---|---|
| ? | /\d?/ 代表前边的字符出现0或1次 |
| + | 代表前边的字符出现1到多次 |
| * | 代表前边的字符出现0到多次 |
| {n} | 代表前边的字符出现n次 |
| {n,} | 代表前边的字符出现n到多次 |
| {n,m} | 代表前边的字符出现n到m次 |
| ([ab])\1 | 反向引用,匹配aa或者bb符 |
| ([ab])\1+ | 反向引用,匹配连续多个a或者多个b符 |
| (?:pattern) | 匹配检验 windows(?:2000|NT|98) 等同于 windows2000|windowsNT|windows98 |
| (?=pattern) | 正向肯定预查 |
| (?!pattern) | 正向否定预查 |
4) 修饰符
| 字符 | 原单词 | 含义 |
|---|---|---|
| g | global | 全局匹配,最多用于捕获,匹配时很少有 |
| i | ignoreCase | 忽略大小写 |
| m | multiline | 多行匹配 |
5) 使用方法介绍
| 方法 | 描述 |
|---|---|
| test | 在字符串中查找匹配的RegExp方法,匹配到返回true(未匹配到返回false) |
| exec | 在字符串中查找匹配的RegExp方法,匹配到返回一个数组(未匹配到返回null) |
| match | 在字符串中查找匹配的String方法,匹配到返回一个数组(未匹配到返回null) |
| matchAll | 在字符串中查找所有匹配的String方法,匹配到返回一个迭代器) |
| replace | 在字符串中查找所有匹配的String方法,并且使用替换掉匹配的字符串) |
6) 使用方法案例
6.1. test()
//检验有效数字,数字前可以有-+号,小数的话,点后面必须有值,
var reg = /^[+\-]?(\d|[1-9]\d+)(\.\d+)?$/;
var a='01',b='0.',c='+24342',d='-+123';
console.log(reg.test(a),reg.test(b),reg.test(c),reg.test(d));
//=>false false true false
//检验密码必须包含数字、大写字母、小写字母并且位数在8-15
//(?=.*[A-Z])使用正向预查,前面可以有或者没有任意字符,必须有一个大写字母
reg = /^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,15}$/;
reg.test("AAaa23412")//true
6.2. exec() 捕获(查询)返回一个数组
// 捕获的贪婪性 一次获取 会尽可能多的去获取内容 想解决这个贪 就在量词后边 加一个?
// 捕获的懒惰行 只获取一次;解决这个懒 使用修饰符 g
var str = 'asda2009cccc2022,as,123dd22';
var reg = /\d+/
console.log(reg.exec(str));//['2009', index: 4, input: 'asda2009cccc2022,as,123dd22', groups: undefined]
//匹配数字,只能找到第一个2009符合,找到后就立马停止,再次执行仍然是2009
console.log(reg.exec(str));//['2009', index: 4, input: 'asda2009cccc2022,as,123dd22', groups: undefined]
// 加上g全局查找效果如何呢?
reg = /\d+/g;
console.log(reg.lastIndex);//0 lastIndex 代表的就是当次匹配对应字符串的开始索引0
console.log(reg.exec(str));//['2009', index: 4, input: 'asda2009cccc2022,as,123dd22', groups: undefined]
console.log(reg.lastIndex);//8 这次再执查找的索引为8,也就是从上次查找内容的最后的索引后面开始的
console.log(reg.exec(str));//['2022', index: 12, input: 'asda2009cccc2022,as,123dd22', groups: undefined]
6.2.1拓展通过exec编写一个execAll方法
str = 'asda2009cccc2022,as,123dd22';
reg = /\d+/g;
RegExp.prototype.execAll = function (str) {
if (!this.global) {
throw new Error("没加g")
}
this.lastIndex = 0; // 防止这个正则的lastIndex不是0而导致获取到的内容不对
let ary = [];
let item = this.exec(str)
while (item) {
ary.push(item[0])
item = this.exec(str)
}
return ary
}
console.log(reg.execAll(str)); //['2009', '2022', '123', '22']
console.log(reg.execAll(str));//再次运行结果一样 ['2009', '2022', '123', '22']
6.2.2 ()的作用
之前()描述过就是一个特殊元字符,提升优先级用来表示一个整体,现在把它在捕获方法里使用后,()也代表一个小组,在整个正则表达式中,遇到一个()就会执行一次捕获,捕获的结果会统一返回到结果的数组里面
reg = /^\d{6}(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/
str = '130425199110134526'
res1 = reg.exec(str)// ['130425199110134526', '1991', '10', '13', '2', '6', index: 0, input: '130425199110134526', groups: undefined]
//分析结果可以看到,数组从0-n项依次式每次捕获的字符串
//res[0] =>'130425199110134526'//全局捕获对应的结果
//res[1] =>'1991'//里面(\d{4})项 捕获对应的结果
//......
//res[5] =>'6'//里面(\d|X)项 捕获对应的结果
6.3.字符串的match
match是string类型的方法,可以利用正则匹配完成捕获功能,类似RegExp的exec方法
6.3.1 功能对比RegExp.exec
reg = /^\d{6}(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/
str = '130425199110134526'
res1 = reg.exec(str)
res2 = str.match(reg)
console.log(res1, res2)
//['130425199110134526', '1991', '10', '13', '2', '6', index: 0, input: '130425199110134526', groups: undefined]
//['130425199110134526', '1991', '10', '13', '2', '6', index: 0, input: '130425199110134526', groups: undefined]
//运行结果一样
那么我们把正则表达式加上g呢?再看下结果
reg = /^\d{6}(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/g
res1 = reg.exec(str)
res2 = str.match(reg)
console.log(res1, res2)
//['130425199110134526', '1991', '10', '13', '2', '6', index: 0, input: '130425199110134526', groups: undefined]
//['130425199110134526']
//很明显macth只能匹配一次全局的,不会理会()小分组的内容
6.4.字符串的replace
String.prototype.replace()
str.replace(regexp|substr, newSubStr|function)
这个方法丝毫不陌生,搭配上正则使用后,功能拓展更大
'1-2-3-4'.replace('-','');//'12-3-4'
'1-2-3-4'.replace(/-/,'');//'12-3-4'
'1-2-3-4'.replace(/-/g,'');//'1234'
'1-2-3-4'.replace(/-/g,a=>'')//'1234'
7) 拓展面试题应用
很多功能可能会通过字符串方法,数组方法解决,如果通过正则方式解决会提高B格,让面试官对你高看一些
7.1. 简单实现获取url参数对象
//定义一个比较简单的url,暂时不考虑特殊清楚比如字符包括关键字、name重复等问题
let str = 'https://www.baidu.com/s?name=xiaom&age=30&id=0xc1'
function queryURL(str, key) {
let reg = /([^?&]+)=([^&]+)/g //name=xiaom 前面(不是?或者&)中间是= 不以&结尾 的字符串部分
let obj = {};
str.replace(reg, function (a, b, c) {//a:name=xiao,b:name,c:xiaom
obj[b] = c
})
return key ? obj[key] : obj
}
console.log(queryURL(str)); //{name: 'xiaom', age: '30', id: '0xc1'}
7.2. 驼峰命名 get-element-by-id ---> getElementById
let str2 = 'get-element-by-id'
let res = str2.replace(/-(\w)/g, function (a, b) {
return b.toUpperCase() //函数的返回结果 是把大正则匹配的内容给替换了
})
console.log(res);//getElementById
7.3. 字符串里面大小写反转 AA1a--->aa1A
let str3 = 'DFGDFdfgeSRgDSFGdfGERdgDFgAERddeRE3453函数i职能划分'
let res3 = str3.replace(/[a-zA-Z]/g, function ($0) {
if ($0.toLowerCase() === $0) {//'A'!='A'.toLowerCase() ,'a'=='a'.toLowerCase()
return $0.toUpperCase()
} else {
return $0.toLowerCase()
}
})
7.4. 查找一个字符串中出现次数最多的字符
let str = 'sdfgsdge4rtsgfsdfgsrthhcxvhstgsfgsf',
str2 = str.split('').sort().join('')//4cdddefffffgggggghhhrrsssssssstttvx
let maxNum = 0, maxStr = '';
str2.replace(/(\w)\1+/g, function ($0) {
if ($0.length > maxNum) {
maxNum = $0.length
maxStr = $0
}
})
console.log(maxNum, maxStr)//8 'ssssssss'
7.5. 按照模板输出对象内容
let template = '我是{{name}},年龄{{age}},性别{{sex}}';
let data = {
name: '姓名',
age: 18
}
function render(template, data) {
let res = template.replace(/\{\{(\w+)\}\}/g, function (a, b) {
return data[b]//b---> {{name}}
})
return res
}
console.log(render(template, data))// '我是姓名,年龄18,性别undefined'
7.6. 千分符
let str = '12345666.048586' //12,345,666.048586
function qian(str) {
//出现,最少千分位1111,匹配4位数
//匹配某个数字\d 后面跟着至少1个(三位数)且结尾
let reg = /\d(?=(\d{3})+$)/g
let xiaoshu = str.split('.')[1]
str = str.split('.')[0]
return str.replace(reg, function (a) {
return a + ','//匹配到次数然后给他加给“,”
}) + (xiaoshu ? '.' + xiaoshu : '')
}
console.log(qian(str))// '12,345,666.048586'
如果没有小数可以简写
'1233454899992'.replace(/\d(?=(\d{3})+$)/g,'$&,');//'1,233,454,899,992'
// $& 插入匹配字符串