正则基础
正则的功能
1)匹配
//1)匹配 判断一个字符串是否符合制定的规则->test 语法:reg.test(str)
let reg = /\d/ // -> 包含一个0-9之间的数字
console.log(reg.test('红')) //false
console.log(reg.test('小红11')) //true
2)捕获
//2)捕获 把字符串中符合我们正则规则的内容捕获到->test 语法:reg.exec(str)
let reg = /\d/ // -> 包含一个0-9之间的数字
console.log(reg.exec('红')) //null
console.log(reg.exec('小红11')) //["1", index: 2, input: "小红11", groups: undefined]
创建正则
//如何创建一个正则
//字面量方式:
let reg = /\d/
// //实例创建方式:
let reg = new RegExp('')
=======================================================>
//创建正则的区别
let name ='xiaohong'
//在字面量方式中,//之间包起来的所有的内容都是元字符,有的具有特殊的意义,大部分都是代表本身含义的普通元字符
// let reg = /^\d+"+name+"\d+$/
// console.log(reg.test('11xiaohong11')) //false
// console.log(reg.test('11"""nameeee"11')) //true
//对于这样的需求,我们只能使用实例创建的方式了
let reg = new RegExp("^\\d+" + name + "\\d+$","g")
console.log(reg.test('11xiaohong11')) //true
console.log(reg.test('11"""nameeee"11')) //false
//字面量方式和实例创建的方式在正则中的区别?
/**
* 1)字面量方式中出现的一切都是元字符,所以不能进行变量值的拼接,而实例创建的方式是可以的
* 2)字面量方式中直接写\d就可以,而在实例中需要把它转义 \\d
*
*/
元字符
//元字符:
//每一个正则表达式都是由元字符和修饰符组成的
// [元字符] -> 在//之间具有意义的一些字符
// 1、具有特殊意义的元字符
// \:转义字符,转义后面字符所代表的含义
// ^:以某一个元字符开始
// $:以某一个元字符结尾
// \n:匹配一个换行符
// .:除了\n以为的任意字符
// ():分组 -> 把一个大正则本身划分成几个小的正则
// let reg = /^(\d+)xiaohong(\d+)$/
// x|y:x或者y中的一个
// [xyz]:x或者y或者z中的一个
// [^xyz]:除了三个以外的任何一个字符
// [a-z]:a-z之间的任何一个字符
// [^a-z]:除了a-z之间的任何一个字符
// \d:一个0-9之间的数字 \D:除了0-9之间的数字以外的任何字符
// \b:匹配一个边界符
// \w:数字、字母、下划线中的任意一个字符 [0-9a-zA-Z_]
// \s:匹配一个空白字符 空格、一个制表符、换页符...
// 2、代表出现次数的量词元字符
// *:出现零到多次
// +:出现一到多次
// ?:出现零次或者一次
// {n,}:出现n到多次
// {n,m}:出现n到m次
// 1、具有特殊意义的元字符
let reg = /\d/
console.log(reg.test('小红11')) //true
let reg2 = /^\d$/ // -> 只能是一个0-9之间的数字
console.log(reg2.test('9')) //true
console.log(reg2.test('012')) //false
reg = /^\d$/ // -> 只能是一个0-9之间的数字
// 2、代表出现次数的量词元字符
let reg = /^\d+$/
console.log(reg.test('小红11')) //false
console.log(reg.test('0121')) //true
//一个简单的验证手机号的正则:11位数字,第一位是1
let reg = /^1\d{10}$/
console.log(reg.test('18207598505'))
// .:
let reg = /^0.2$/ // -> 以0开头,以2结尾,中间可以是除了\n的任意字符
console.log(reg.test('0.2')) //true
console.log(reg.test('0-2')) //true
let reg2 = /^0\.2$/ // .前面有\,代表已经被转义,成为了普通的.
console.log(reg2.test('0.2')) //true
console.log(reg2.test('0-2')) //false
中括号 []
//[]
//1、在中括号中出现的所有的字符都是代表本身意思的字符(没有特殊的含义)
// let reg = /^[.]$/
// console.log(reg.test('1')) //false
// console.log(reg.test('.')) //true
//2、中括号不识别两位数
// let reg = /^[12]$/ // -> 1或者2中的一个
// let reg = /^[12-68]$/ // -> 1、2-6、8 三个中的一个
//3
// let reg = /^[\w-]$/ //->数字、字母、下划线、- 中的一个
//()
//1、分组的作用:改变x|y的默认的优先级
// let reg = /^18|19$/
//18,19,191,189,119,819,1819
// let reg = /(^18|19$)/
//18,19
//1、有效数字的正则: 正数、负数、零、小数
//1)"."可以出现也可以不出现,但是一旦出现,后面必须跟着一位或者多位数字
//2)最开始可能有 +/- 也可以没有
//3)整数部分,一位数可以是0-9之间的一个数,多位数不能以0开头
// let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/
//12.3
//12
//-12
//+12
//0.2
//09
//2、年龄介于18~65之间 18-19 20-59 60-65
// let reg = /^(1[8-9]|[2-5]\d|6[0-5])$/
// console.log(reg.test('20'))
//3、验证邮箱的正则(简版)
//左边:数字、字母、下划线
//1032098274@qq.com
// let reg = /^[\w.-]+@[0-9a-zA-Z]+(\.[a-zA-Z]{2,4}){1,2}$/
//4、中国标准真实姓名 2-4位汉字
// let reg = /^[\u4e00-\u9fa5]{2,4}$/
//5、身份证号码
let reg = /^([0-9]{17}[0-9|xX])$/
exec ->正则的捕获
//exec ->正则的捕获
//1、
//每一次捕获的时候都是先进行默认的匹配,如果没有匹配成功的,捕获的结果是null,只有有匹配的内容我们才能捕获到
//捕获的内容格式
//1)捕获的到内容是一个数组,数组中的第一项是当前大正则捕获的内容
//index:捕获内容在字符串中开始的索引位置
//input:捕获的原始字符串
//2、正则捕获的特点
//1)懒惰性 ->每一次执行exec只捕获第一个匹配的内容,在不进行任何处理的情况下,再执行多次捕获,捕获的还是第一个匹配的内容
//lastIndex:是正则每一次捕获在字符串中开始查找的位置,默认的值是0
//2)如何解决懒惰性? 在正则的末尾加一个修饰符"g"
//修饰符:g、i、m
//global(g):全局匹配
//ignoreCase(i):忽略大小写匹配
//multiline(m):多行匹配
let reg = /\d+/;
let str = '111小红222'
console.log(reg.lastIndex) // -> 0
let res = reg.exec(str)
console.log(reg.lastIndex)
console.log(res) //["111", index: 0, input: "111小红222", groups: undefined]
console.log(reg.lastIndex) // -> 0 说明第二次捕获的时候也是要从字符串索引0处开始查找
// //第二次通过exec捕获的内容还是第一个 "111"
res = reg.exec(str)
console.log(res)//["111", index: 0, input: "111小红222", groups: undefined]
//原来:加了全局修饰符g,正则每一次捕获姐俗话,我们的lastIndex的值都变为了最新的值,下一次捕获从最新的位置开始查找,这样就可以把所有需要捕获的内容都获取到了
let reg = /\d+/g;
let str = '111小红222'
console.log(reg.lastIndex)
let res = reg.exec(str)
console.log(res) //["111", index: 0, input: "111小红222", groups: undefined]
console.log(reg.lastIndex) //3
res = reg.exec(str)
console.log(res)//["222", index: 5, input: "111小红222", groups: undefined]
//3)获取正则捕获的所有内容(一定不要忘记加g)
let reg = /\d+/g
let str = 'xiaohong2016xiaohong2017xiaohong2018520'
let arr = []
let res = reg.exec(str)
while(res){
arr.push(res[0])
res = reg.exec(str)
}
console.log(arr)
//4)贪婪性 正则的每一次捕获都是按照匹配最长的结果捕获的,例如:2符合正则,2016也符合正则,默认捕获的是2016
let reg = /\d+/g //->出现一到多个0-9之间的数字
let str = 'xiaohong2016xiaohong2017xiaohong2018520'
//5)如何解决正则的贪婪性 ->在量词元字符后面添加一个?即可
//?在正则中有很多的作用:
//放在一个普通的元字符后面代表出现0-1次 /\d?/ -> 数字可能出现也可能不出现
//放在一个量词的元字符后面是取消捕获时候的贪婪性
let reg = /\d+?/g
let str = 'xiaohong2016xiaohong2017xiaohong2018520'
console.log(reg.exec(str))//["2"...]
//3、字符串中的match方法 -> 把所有和正则匹配的字符都获取到
let reg = /\d+?/g
let str = 'xiaohong2016xiaohong2017xiaohong2018520'
let ary = str.match(reg)
console.log(ary)
//虽然在当前的情况下 match比我们的exec更加的简便一些,但是match中存在一些自己处理不了的问题:在分组捕获的情况下吗,match只能捕获到大正则匹配的内容,而对于小正则捕获的内容是无法获取的
正则分组
//正则分组:
//1、改变优先级
//2、分组应用
//\2代表和第二个分组出现一模一样的内容; \1和第一个分组出现一模一样的内容
//一模一样:和对应的分组中的内容的值都要一样
let reg = /^(\w)\1(\w)\2$/
console.log(reg.test('zzff')) //true
console.log(reg.test('z0f_')) //false
//3、分组捕获 -> 正则在捕获的时候,不仅仅把大正则匹配的内容捕获到,而且还可以把小分组匹配的内容捕获到
// (?:) 在分组中, ?: 的意思是只匹配不捕获
let reg = /^(\d{2})(\d{3})(\d{4})$/
let str = '131245678'
console.log(reg.exec(str)) // ["131245678", "13", "124", "5678", index: 0, input: "131245678", groups: undefined]
// //[0] -> 大正则匹配的内容
// //[1] -> 第一个分组捕获的内容
// //[2] -> 第二个分组捕获的内容
let reg1 = /^(\d{2})(?:\d{3})(\d{4})$/
let str1 = '131245678'
console.log(reg1.exec(str)) // ["131245678", "13", "5678", index: 0, input: "131245678", groups: undefined]
let reg = /xiaohong(\d+)/g
let str = 'xiaohong123xiaohong456xiaohong789'
//用exec执行三次,每一次不仅仅把大正则匹配的获取到,而且还可以获取到第一个分组匹配的内容
console.log(reg.exec(str))//["xiaohong123", "123"...]
console.log(reg.exec(str))//["xiaohong456", "456"...]
console.log(reg.exec(str))//["xiaohong789", "789"...]
//而match只能捕获大正则匹配的内容
console.log(str.match(reg)) //["xiaohong123", "xiaohong456", "xiaohong789"]
replace使用
//replace:把原有的字符替换成新的字符
//在不使用正则的情况下,每当执行一次只能替换一个字符
let str = 'xiaohong2018xiaohong2019'
console.log(str.replace(/xiaohong/g,'xiaohongmao')) //xiaohongmao2018xiaohongmao2019
//replace第一项的值是一个正则它的实现原理
//首先和exec捕获一样,把所有和我们正则匹配的都捕获到,然后把捕获的内容替换成我们需要替换的新内容
//-> /xiaohong/g 按照这个正则把str中所有可以匹配的都捕获到,然后统一都替换成'xiaohongmao'
let str = 'xiaohong2018xiaohong2019'
let reg = /xiaohong/g
console.log(reg.exec(str)) //["xiaohong", index: 0, input: "xiaohong2018xiaohong2019", groups: undefined]
console.log(reg.exec(str)) //["xiaohong", index: 12, input: "xiaohong2018xiaohong2019", groups: undefined]
str = str.replace(/xiaohong/g,function(){
console.log(arguments)
//第一次执行匿名函数结果 -> ["xiaohong", 0, "xiaohong2018xiaohong2019", callee: ƒ, Symbol(Symbol.iterator): ƒ]
//第二次执行匿名函数结果 -> ["xiaohong", 12, "xiaohong2018xiaohong2019", callee: ƒ, Symbol(Symbol.iterator): ƒ]
return 'xiaohongmao'
})
//第二个参数换成一个函数
//1)匿名函数执行多少次,取决于正则能在字符串中捕获多少次 ->正则捕获量词,所以匿名函数也执行两次
//2)每一次执行匿名函数,里面传递的参数值arguments和我们自己通过exec捕获到的结果是非常类似的(即使正则有分组,我们统一可以通过arguments获取到分组捕获的内容)
//3)return 返回的结果是啥,就相当于把当前这一次大正则捕获的内容替换成你返回的内容
let str = 'xiaohong2018xiaohong2019'
str = str.replace(/\d+/g,function(){
console.log(arguments[0]) //每一次执行匿名函数把我们大正则捕获的内容获取到
return '520'
})
console.log(str) //xiaohong520xiaohong520
let str = 'xiaohong2018xiaohong2019'
str = str.replace(/(\d+)/g,function(){
// console.log(arguments[1]) //获取每一次执行匿名函数正则捕获到的第一个分组中的内容
console.log(RegExp.$1)
})
console.log(str) //xiaohong520xiaohong520
//RegExp.$1 -> 获取第一个分组捕获的内容
//1、数字替换成中文
let str = '20191011'
let arr = ['零','壹','贰','叁','肆','伍','陆','柒','捌','玖']
str = str.replace(/\d/g,function(){
let idx = arguments[0]
return arr[idx]
})
console.log(str) //贰零壹玖壹零壹壹
//2、获取一个字符串中出现次数最多的字符,并且获取出现的次数
// let str = 'xiaohongxiaohongxiaohonghahahahh'
// //1)获取每一个字符出现的次数
let obj = {}
str = str.replace(/[a-z]?/gi,function(){
if(obj[arguments[0]] >= 1){
obj[arguments[0]]++
}else{
obj[arguments[0]] = 1
}
})
// //2)获取最多出现的次数
let maxNum = 0
for(let key in obj){
obj[key] > maxNum ? maxNum = obj[key] : null
}
//3)把所有符合出现maxNum次数的都获取到
let ary = []
for(let key in obj){
obj[key] === maxNum ? ary.push(key): null
}
console.log(obj)
console.log(ary)
//3、模板引擎实现的初步原理
let str = 'my name is {0},my age is {1},i come from {2}, i love {3}~'
let ary = ['小红','22','china','see see you']
str = str.replace(/{(\d+)}/g,function(){
return ary[arguments[1]]
})
console.log(str) //my name is 小红,my age is 22,i come from china, i love see see you~
// 4、URL地址参数获取
let str = 'http://kbs.sports.qq.com/kbsweb/game.html?mid=10000&cid=1467086&app=1.0'
let reg = /([^?=&]+)=([^?=&]+)/g
let obj = {}
str.replace(reg,function(){
obj[arguments[1]] = arguments[2]
})
console.log(obj)
let obj = {}
let res = reg.exec(str)
while(res){
obj[res[1]] = res[2]
res = reg.exec(str)
}
console.log(obj)
//==========================================================================>
//正则时间格式化
let str = '2019-10-12 22:07:00';
let reg = /^(\d{4})[-/](\d{1,2})[-/](\d{1,2}) +(\d{1,2}):(\d{1,2}):(\d{1,2})$/;
let ary = [];
str.replace(reg,function(){
ary = [].slice.call(arguments)
ary = ary.slice(1,7)
})
console.log(ary)
//2019年10月12日 22时07分00秒
//设定好目标时间格式
let resStr = '{0}年{1}月{2}日 {3}时{4}分{5}秒'
let reg1 = /{(\d+)}/g
resStr = resStr.replace(reg1,function(){
let num = arguments[1]
return ary[num].length <= 1? '0'+ ary[num] :ary[num];
})
console.log(resStr)