1.正则表达式
regular expression:简写 RegExp
- 1.用来处理字符串的规则
- 2.正则表达式用来处理字符串规则: 只能处理字符串
- 3.它是一个规则:
- 可以验证字符串是否符合某个规则(test),
- 也可以把字符串中符合规则的内容捕获到(exec/match...)
1.学正则就是用来制定规则的(是否包含数字)
//1.字符串中没有出现数字
let str = "good good study,day day up!";
let reg = /\d+/;//=>出现0到多个数字
console.log(reg.test(str));
//=>false(str里面没有出现任何的数字,哪怕是出现了一个1,都没有)
//2.出现了一次数字 就是true
let str = "good 123good study,day day up!";
let reg = /\d+/;//=>出现0到多个数字
console.log(reg.test(str));
//=>true(str里面出现了数字,哪怕是出现了一个1,都是true)
2.也可以把字符串中符合规则的内容捕获到 (exec/mach...)
let str = "good 123good study,day day up!";
let reg = /\d+/;
str = '2019-08-06';
console.log(reg.exec(str));//=>["2019", index: 0, input: "2019-08-06", groups: undefined]
3.控制台可以输出 dir(RegExp) 会查看到原型prototype会有test exec两个查看是否符合规则或者是否捕获到的方法
2.编写正则表达式
创建方式有两种
- 1.字面量创建方式(两个斜杠之间包起来的,都是用来描述正则规则的元字符)
let reg1=/\d+/;
- 2、构造函数模式创建两个参数:元字符字符串,修饰符字符串
let reg2=new RegExp('\\d+');
3.正则表达式由两部分组成:元字符、修饰符
- 1、常用的元字符-——量词元字符:设置出现的次数
* 零到多次
+ 一到多次
? 零次或者一次
{n} 出现n次
{n,} 出现n到多次
{n,m} 出现n到m次
//例子:
\d :0到9的一个数字
\d* :0到多次连续的数字
\d+ :0到多次
\d? :0到1次
\d{5}:一个5位数
\d{5,}:5位或者5位以上的数字
\d{5,10}:5位数到10位数
- 2、特殊元字符:单个或者组合在一起代表特殊的含义
. : 除\n(换行符)以外的任意字符
.+ : 除\n以外 1到多个的任意字符
\ : 转义字符(普通=>特殊=>普通)
^ : 以哪个元字符开始
$ : 以哪个元字符结束
\n: 换行符
\d: 0-9之间的一个数字
\D: 非0-9之间的数字,(大小写正好是相反的)
\w: 数字、字母、下划线任意一个字符
\s:一个空白符(包含空格 制表符 换页符)
\t: 一个制表符(一个tab,四个空格)
\b: 匹配单词的边界
x|y: x或者y中的一个字符 1|9(1或者9任意字符) 1|5|9(1或者5或者9任意字符)
[xyz]:x y z中的任意一个字符 [ablcsd3725]这堆中的任意一个字符
[^xy]:除了xy以外的任意字符
[a-z]:指定a-z这个范围的任意字符 例如下:[0-9a-zA-Z]:0-9中的任意一个字符,a-z中的任意一个字符,A-Z中的任意一个字符或者_ [0-9a-zA-Z]===\w
[^a-z]:不是以a-z开始的字符
():正则中的分组符号
(?:):只匹配不捕获
(?=):正向预查
(?!):负向预查
- 3、特殊元字符:单个或者组合在一起代表特殊的含义
/zhangsan/ 此正则匹配的就是‘zhangsan’
- 4.修饰符
常用的修饰符:img
i => ignoreCase 忽略单词大小写匹配
m => multiline 可以进行多行匹配
g => global 全局匹配
//例子:
/A/.test("lalala")//=>false(这里的a是小写,所以没有大写A就返回false)
/A/i.test("lalala")//=>true(a 但是i是忽略大小写的 )
4.元字符详细解析
1.开始(^ $)都不加:正则规则是\d 0到9之间的数字,字符串中出现数字就可以
//0-9之间的数字
let reg=/\d/;
//(reg中是\d 0到9之间的数字 这是规则,而字符串中没有数字)
console.log(reg.test("zhangsan"));//=>false
console.log(reg.test("2020zhangsan"));//=>true
console.log(reg.test("zhangsan2019"));//=>true
2.以数字结尾 $
//以数字结尾
let reg=/\d$/;
//reg中是\d$ 以0到9之间的数字结尾规则,而字符串结尾没有数字
console.log(reg.test("zhangsan"));//=>false
//这个是以数字开始,而结尾没有出现任何数字
console.log(reg.test("2020zhangsan"));//=>false
console.log(reg.test("zhangsan2019"));//=>true
3.^ $两个都不加:字符串中包含符合规则的内容即可
//(0-9之间的数字出现1到多次)
let reg=/\d+/;
4.^ $两个都加,字符串只能是和规则一致的内容
let reg=/^\d+$/;//(以数字开始,以数字结尾)
5.举个例子:验证手机号码
//分析:手机号码是11位数字,以1开始 10个数字结束
let reg=/^1\d{10}/;
5.(/)转义字符
- ^ . $ 三个字符制定规则
//(以2开始 点是中间任意字符除换行以外 以3结尾)
let reg=/^2.3$/;
console.log(reg.test("2@3"));//=>true
console.log(reg.test("2.3"));//=>true
//(以数字2开始 3结尾中间没有任何字符,规则是中间可以出现任何字符)
console.log(reg.test("23"));//=>false
- 基于转义字符,让其只能代表小数点
//(以2开始 中间出现点 以3结尾)
reg =/^2\.3$/;
console.log(reg.test("2.3"));//=>true
//(以2开始,3结尾 但是中间没有出现点 所以是false)
console.log(reg.test("23"));//=>false
- 正则/d的输出
//(单纯的字符串 'd')
let str='\d';
//(0到9开始 0-9 结尾)也就是数字开始 数字结尾
let reg=/^\d$/;
//字符串'd' 没有符合reg的规则 所以是false
console.log(reg.test(str));//=>false
- 转义为 \d
let str='\\d';//=>\d的意思
let reg=/^\\d$/;//=>\d的意思
console.log(reg.test(str));//=>true
5.控制台输出
'张三\n李四' //=>'张三
// 李四'
'张三\\n李四' //=>'张三\n李四'
6.x|y
- x|y
let reg= /^18|29$/;
console.log(reg.test('18'));//=>true (以18或29 任何一个)
console.log(reg.test('29'));//=>true
console.log(reg.test('129'));//=>true (以1开头 中间是8或者2 以9结尾)
console.log(reg.test('189'));//=>true
console.log(reg.test('1829'));//=>true (以1、8开头 或 以2、9结尾)
console.log(reg.test('829'));//=>true
console.log(reg.test('182'));//=>true
2.直接x|y会存在很乱的优先级为题,一般我们伴随着小括号进行分组,因为小括号改变处理的优先级=>小括号分组
reg=/^(18|29)$/;
console.log(reg.test('18'));//=>true
console.log(reg.test('29'));//=>true
console.log(reg.test('129'));//=>false(是以18开始或者29结束,都可以 而129不符合)
7.[]
1.中括号出现的字符一般都代表本身的含义
let reg=/^[@+]$/;//(以@或+开始或者结尾的意思)
console.log(reg.test('@'));//=>true
console.log(reg.test('+'));//=>true
//这里是两个@,因为中括号里面出现的是本身的意思,+不是多次的意思
console.log(reg.test('@@'));//=>false
//@或+开始或者结尾,不能同时出现
console.log(reg.test('@+'));//=>false
2.\d在中括号还是0-9
reg=/^[\d]$/;//=>\d在中括号还是0-9
console.log(reg.test('d'));//=>false (此字符串中没有出现数字)
console.log(reg.test('\\'));//=>false (此字符串中没有出现数字)
console.log(reg.test('9'));//=>true
3.中括号不存在多位
reg=/^[18]$/;//(以1或8开始或者结束)
console.log(reg.test('1'));//=>true
console.log(reg.test('8'));//=>true
console.log(reg.test('18'));//=>false
4.中括号中不存在多位数
reg=/^[10-29]$/;//(1或 0到2 或9)
console.log(reg.test('1'));//=>true
console.log(reg.test('9'));//=>true
console.log(reg.test('0'));//=>true
console.log(reg.test('2'));//=>true
console.log(reg.test('10'));//=>false(中扩中不存在多位数)
8.验证是否为有效数字
//规则分析:
//1.可能出现 + -号,也可能不出现. [+ -]?
//2.一位0-9都可以,多位首位不能为0 [\d(1-9)\d+]
//3.小数部分可能没有,一旦有后面必须有小数点+数字 (\.\d+)?
let reg=/^[+-]? (\d([1-9]\d+))(\.\d+)?$/;
9.验证输入的用户名是否为有效
- 1.正则写法
//分析:
//1.数字、字母、下划线 /w
//2. 6-16位
let val=userpassInp.value;
let reg=/\w{6,16}$/;
let flag=reg.test(val);
- 2.js原生写法
let val=userpassInp.value;
function checkpass(val){
if(val.length<6 || val.length>16){
alert('长度必须是6-16位之间!');
return;
}
let area=['a','b',...'_'];//=>包含数字、字母、下划线
for(let i=0;i<val.length;i++){
let char=val[i];
if(!area.includes(char)){
alert("格式不正确");
return;
}
}
}
10.验证真是姓名
//分析:
//1、汉字 /^[\u4E00-\u9FA5]$/
//2.名字的长度2~10;
//3.可能有译名·汉字 ([\u4E00-\u9FA5]{2,10}) {0,2} (点不出现或者出现两次)
let reg=/^([\u4E00-\u9FA5]{2,10})(·[\u4E00-\u9FA5]{2,10}){0,2}$/;
11.验证邮箱的正则
let reg=/^\w+((-\w)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/;
//分析
//1.开头是数字、字母、下划线 (1到多位)
//2.还可以是_数字字母下划线或者数字 字母下划线,整体零到多次
//=>邮箱的名字是由"数字、字母、下划线、- ·"几部分组成的,但是 - · 不能连续出现,也不能作为开始
// \w((-\w)|(\.\w+))
//3.后面紧跟着数字、字母(1到多位)
// @[A-Za-z0-9]+
//4.对@后面的补充
//多域名 .com.cn
// 企业邮箱 zxt@zhufeng-peixun-office.com
// ((\.|-)[A-Za-z0-9]+)*
//5.这个匹配的是最后域名(.com/.cn/.org/.edu/.net...)
// \.[A-Za-z0-9]+
12.身份证号的正则
//分析:简写
//1.一共18位
//2.最后一位可能是x(代表10)
let reg=/^\d{17}(\d|X)$/;
//分析:详细版
//1.身份证前六位:省市县 130828
//2.中间八位:年月日
//3、最后四位:最后一位可能是X 倒数第二位=>偶数 女 奇数 男 其余都是经过算法算出来的
//捕获的结果是数组,包含每一个小分组单独获取的内容
let reg=/^({\d{6}})(\d{4})(\d{2})(\d{2})\d{2}(\d)(\d|X)$/;
reg.exec("130828199012040617");//=>["130828199012040617",'130828',"1990","12","04","1","7"...]
// 小括号分组的第二个作用:分组捕获,不仅可以把大正则匹配的信息捕获到,还可以单独捕获到每个小分组的内容
13.正则的两种创建方式的区别
构造函数因为传递的是字符串,\需要写两个才代表斜杠
//1.普通的创建正则的方式
let reg=/\d+/g;
//2.构造函数的创建方式
let reg=new.RegExp('\\d'+'g');
14.正则表达式是中间的部分内容是变量存储的值
- 1.两个斜杠中间包起来的都是元字符(如果正则中要包含某个变量的值,则不能使用字面量的方式创建)
let type='zhangsan';
reg=/^@"+type+"@$/;//("可以出现多次,e可以出现多次)
console.log(reg.test("@zhangsan@"));//=>false
console.log(reg.test('@"""typeeeee"@'));//=>true
- 2.这种情况只能使用构造函数方式(因为它传递的规则是字符串,只有这样子才能进行字符串拼接)
reg=new RegExp("^@+type+@$");
console.log(reg.test("@zhangsan@"));//=>true
15.实现正则捕获的方法
- 1.正则RegExp.prototype上的方法:exec test
- 2.字符串string.prototype上支持正则表达式处理的方法:replace match splice
1.exec把数字都捕获到
let str="zhangsan2019yangfan2020qihang2021";
let reg=/\d+/;
console.log(reg.exec(str));
//=>["2019",index:7,input:"zhangsan2019yangfan2020qihang2021"]
2.基于exec实现正则的捕获
- 1.捕获到的结果是null或一个数组
- 第一项:本次捕获到的内容
- 其余项:对应小分组本次单独捕获到的内容
- index:当前捕获内容在字符串中的起始索引
- input:原始字符串
- 2.每执行一次exec,只能捕获到一个符合正则规则的
//实现正则捕获的前提是:当前正则要和字符串匹配,如果不匹配捕获的结果是null
let str="zhangsan2019yangfan2020qihang2021";
//(0-9之间的数字可以任何字数开始或结束,中间可以出现多次规则)
let reg=/^\d+$/;
console.log(reg.test(str));//=>false (str中包含字母所以不符合规则)
console.log(reg.exec(str));//=>null
3.reg.lastIndex:当前正则上下文下一次匹配的起始索引位置
- 1.懒惰性捕获的原因:默认情况下lastIndex的值不会被修改,每一次都是从字符串开始位置查找,所以找到的永远只是第一个
- 2.解决办法:全局修饰符g
let str="zhangsan2019yangfan2020qihang2021";
let reg=/\d+/;
//下面匹配捕获是从str索引零的位置开始查找
console.log(reg.lastIndex);//=>0
console.log(reg.exec(str));
//第一次匹配捕获完成,lastIndex没有改变,所以下一次exec依然是从字符串最开始找,
//找到的永远是第一个匹配到的
console.log(reg.lastIndex);//=>0
let reg=/\d+/g;
console.log(reg.exec(str));//=>[2019....]
//设置全局匹配修饰符g后,第一次匹配完 lastIndex会自己修改
console.log(reg.lastIndex);//=>11
console.log(reg.exec(str));//=>[2020....]
console.log(reg.lastIndex);//=>22
console.log(reg.exec(str));//=>[2021....]
console.log(reg.lastIndex);//=>32
console.log(reg.exec(str));//=>null
console.log(reg.lastIndex);//=>0
console.log(reg.exec(str));//=>[2019....]又从0开始循环
let reg=/\d+/g;
if(reg.test(str)){
//验证一下:只有正则和字符串匹配我们在捕获
//基于test匹配验证后lastIndex已经被修改为第一次匹配后的结果,
//所以下一次捕获不在从头开始
console.log(reg.lastIndex);//=>11
console.log(reg,exec(str));//=>[2020....]
}
4.编写一个execAll,执行一次可以把所有匹配的结果捕获到(前提正则一定设置全局修饰符g)
~function execAll(){
function exec(str=""){
//str:要匹配的字符串
//this:RegExp的实例(当前操作的正则)
//=>进来后第一件事,是验证当前正则是否设置了g,不设置则不能在进行循环捕获了,否则会导致死循环
if(!this.global)return this.exec(str);
//=>ary存储最后所有捕获的信息,res存储每一次捕获的内容(数组)
let ary=[];
res=this.exec(str);
while (res){
//=>把每一次捕获的内容res[0]存放到数组中
ary.push(res[0]);
//=>只要捕获的内容部位null,则继续捕获下去
res=this.exec(str);
}
return ary;
}
RegExp.prototype.execAll=execAll;
}();
let str='zhangsan2019yangfan2020qihang2021';
let reg=/\d+/g;
console.log(reg.exec(str));//=>[2019,2020,2021]
5.字符串的match方法,可以在执行一次的情况下捕获到所有匹配的数据(前提是正则也得设置g才可以)
let reg=/\d+/g;
console.log("张三2020@2019李四".match(reg));//=>["2020", "2019"]
console.log('zhangsan2019yangfan2020qihang2021'.match(reg))
;//=>["2019", "2020", "2021"]
16.正则的分组捕获
- 1.身份证号码分组捕获
let str = "130828199012040112";
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/;
console.log(reg.exec(str));
console.log(str.match(reg));
//=>["130828199012040112", "130828", "1990", "12", "04", "1", index: 0, input: "130828199012040112"]
//=>第一项:大正则匹配的结果
//=>其余项:每一个小分组单独匹配捕获的结果
//=>如果设置了分组(改变优先级),但是捕获的时候不需要单独捕获,可以基于?:来处理
- 2.既要捕获到{数字},也想单独的把数字也获取到,例如:第一次找到 {0} 还需要单独获取0
//1.正则分组捕获的方法
let str = "{0}年{1}月{2}日";
//=>不设置g只匹配一次,exec和match获取的结果一致(既有大正则匹配的信息,也有小分组匹配的信息)
let reg = /\{(\d+)\}/;
console.log(reg.exec(str));
console.log(str.match(reg));
//["{0}", "0",...]
//2.封装一个方法,大正则、小分组的捕获方法
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
//console.log(str.match(reg)); //=>["{0}", "{1}", "{2}"]
//多次匹配的情况下,match只能把大正则匹配的内容获取到,小分组匹配的信息无法获取
let aryBig=[],
arySmall=[],
res=reg.exec(str);
while(res){
let [big,small]=res;
aryBig.push(big);
arySmall.push(small);
res=reg.exec(str);
}
console.log(aryBig,arySmall); //=>["{0}", "{1}", "{2}"] ["0", "1", "2"]
- 3.分组的作用:1.改变优先级 2.分组捕获 3.分组引用
let str = "book"; //=>"good"、"look"、"moon"、"foot"...
let reg = /^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/;
//=>分组引用就是通过“\数字”让其代表和对应分组出现一模一样的内容
console.log(reg.test("book")); //=>true
console.log(reg.test("deep")); //=>true
console.log(reg.test("some")); //=>false
let str="book";
let reg=/^[a-zA-Z]([a-zA-Z])\1[a-zA-Z]$/;
console.log(reg.test("book"));//=>true
console.log(reg.test("soom"));//=>true
console.log(reg.test("deck"));//=>false
17.正则捕获的贪婪性
- 1.默认情况下,正则捕获的时候,是按照当前正则所匹配的最长结果来获取的
let str = "张三2019@2020李四";
let reg = /\d+/g;
console.log(str.match(reg)); //=>["2019","2020"]
- 2.在量词元字符后面设置?:取消捕获时候的贪婪性(按照正则匹配的最短结果来获取)
let str = "张三2019@2020李四";
let reg = /\d+/g;
reg = /\d+?/g;
console.log(str.match(reg));
//=>["2", "0", "1", "9", "2", "0", "2", "0"]
18.问号在正则中的五大作用:
- 1.问号左边是非量词元字符:本身代表量词元字符,出现零到一次
- 2.问号左边是量词元字符:取消捕获时候的贪婪性
- 3.(?:) 只匹配不捕获
- 4.(?=) 正向预查
- 5.(?!) 负向预查
19.test也能捕获(本意是匹配)
RegExp.9:获取当前本次正则匹配后,第一个到第九个分组的信息
- 1.test
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"0"
console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"1"
console.log(reg.test(str)); //=>true
console.log(RegExp.$1); //=>"2"
console.log(reg.test(str)); //=>false
console.log(RegExp.$1); //=>"2" 存储的是上次捕获的结果
- 2.exec
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.exec(str)); //=>["{0}", "0"...]
- 3.test
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
// => TEST
// 每一次匹配也和捕获一样,受制于reg.lastIndex(前提也是设置了g修饰符,
//不设置g每一次还是从0开始查找,规则和捕获一样)
console.log(reg.lastIndex); //0
console.log(reg.test(str)); //true
console.log(reg.lastIndex); //3
console.log(reg.test(str)); //true
console.log(reg.lastIndex); //7
console.log(reg.test(str)); //true
console.log(reg.lastIndex); //11
console.log(reg.test(str)); //false
console.log(reg.lastIndex); //0
reg.test(str);
console.log(RegExp.$1); //=>0
//获取当前本次匹配项中,第一个分组匹配的内容($1~$9代表正则中第几个分组中的内容);
//$&是获取当前大正则匹配的内容;
reg.test(str);
console.log(RegExp.$1); //=>1
// 思维:在每一次捕获之前,先判断是否匹配,只有匹配再去捕获
let str = "zhangsan2020";
// 不设置G的情况下,不论TEST还是EXEC都是从索引零的位置开始查找(懒惰性)
let reg = /\d+/;
if (reg.test(str)) {
// console.log(reg.lastIndex); //=>0
console.log(reg.exec(str)); //=>["2020"]
}
// 如果取消了懒惰性,每一次TEST或者EXEC后,都会修改其lastIndex的值,
//导致下一次是在上一次匹配的末尾位置再次查找
reg = /\d+/g;
if (reg.test(str)) {
// console.log(reg.lastIndex); //=>11
console.log(reg.exec(str)); //=>null
}
4.身份证信息捕获每个分组中的信息
let str = "130828199012040617";
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/;
console.log(reg.exec(str));
//=>["130828199012040617", "130828", "1990", "12", "04", "1"...]
console.log(reg.test(str)); //=>true
console.log(RegExp['$&']); //=>"130828199012040617"
console.log(RegExp['$1']); //=>"130828"
console.log(RegExp['$2']); //=>"1990"
console.log(RegExp['$3']); //=>"12"
20.ES6中新增的
- 1.分组具名化(给分组起名字)?<名字>
- 2.后期匹配完,可以基于匹配结果中的groups获取指定名字分组捕获的信息
reg = /^(?<A>\d{6})(?<B>\d{4})(?<C>\d{2})(?<D>\d{2})\d{2}(?<E>\d)(?:\d|X)$/;
let res = reg.exec(str);
console.log(res.groups.A);
console.log(res.groups.E);
21.replace本身是字符串替换的意思
- 1.再不使用正则的情况下,每一次执行REPLACE只能替换一个
let str = "zhangsan2020zhangsan2021"; //=>把"zhangsan"替换成为"张三"
str = str.replace('zhangsan', '张三');
str = str.replace('zhangsan', '张三');
console.log(str); //=>"张三2020张三2021"
let str = "zhangsan2020zhangsan2021";
str = str.replace(/zhangsan/g, '张三');
console.log(str); //=>"张三2020张三2021"
- 2.很多需求不使用正则是无法解决的
//=>把"zhangsan"替换成为"zhangsannifei"
let str = "zhangsan2020zhangsan2021";
//1.replace是实现不了的
str = str.replace('zhangsan', 'zhangsannifei');
console.log(str); //=>"zhangsannifei2020zhangsan2021"
//=>还是从最新字符串索引为零的位置开始查找替换
str = str.replace('zhangsan', 'zhangsannifei');
console.log(str); //=>zhangsannifeinifei2020zhangsan2021
//2.解决方案:正则
let str = "zhangsan2020zhangsan2021";
str = str.replace(/zhangsan/g, 'zhangsannifei');
console.log(str); //=>zhangsannifei2020zhangsannifei2021
// 3.方法的封装
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
// STR=STR.REPLACE(REG,FUNC)
// 1.首先会拿REG和STR去进行匹配捕获,匹配捕获一次,就会把FUNC函数执行一次
// 2.并且会把每一次捕获的结果(和EXEC捕获的结果一样)传递给FUNC函数
// 3.FUNC函数中返回啥,就相当于把原始字符中,大正则匹配的结果替换成啥
str = str.replace(reg, (...args) => {
// console.log(args); => 存储的是每一次正则匹配捕获的结果
//[大正则匹配的、小分组匹配的、捕获的起始索引、原始字符串]
return '@@';
});
console.log(str); //=>"@@年@@月@@日"
22.把时间字符串进行处理
- 1.replac替换
let time = "2019-08-13";
//=>变为"2019年08月13日"
let time = "2019-08-13";
let reg=/(\d{4})-(\d{1,2})-(\d{1,2})$/;
let time=time.replace(reg,'$1年$2月$3日');
console.log(time);
- 2.[str].replace([reg],[function])
//分析:
//1.首先拿REG和TIME进行匹配捕获,能匹配到几次就会把传递的函数执行几次
//(而且是匹配一次就执行一次)
//2.不仅把方法执行,而且REPLACE还给方法传递了实参信息(和exec捕获的内容一致的信息:
//大正则匹配的内容,小分组匹配的信息....)
//3.在函数中我们返回的是啥,就把当前大正则匹配的内容替换成啥
/*
time = time.replace(reg,(big,$1,$2,$3)=>{
//=>这里的$1~$3是我们自己设置的变量
console.log(big,$1,$2,$3);
});
*/
let time = "2019-08-13";
//编写一个正则符合上面的格式并且可以获取到字符串的
let reg=/(\d{4})-(\d{1,2})-(\d{1,2})$/;
//时间等于时间的模板,符合以上正则规则的接受
time = time.replace(reg,(...arg)=>{
let [,$1,$2,$3]=arg;
$2.length<2?$2="0"+$2:null;
$3.length<2?$3="0"+$3:null;
return $1+"年"+$2+"月"+$3+"日";
});
23.单词首字母大写
let str = "good good study,day day up!";
let reg = /\b([a-zA-Z])[a-zA-Z]*\b/g;
//=>函数被执行了六次,每一次都把正则匹配信息传递给函数
//=>每一次ARG:["good","g"] ["good","g"] ["study","s"]...
str = str.replace(reg,(...arg)=>{
let [content,$1]=arg;
$1=$1.toUpperCase();
content=content.substring(1);
return $1+content;
});
console.log(str); //=>"Good Good Study,Day Day Up!"
24.时间字符串的格式化处理
- 1.formatTime:时间字符串的格式化处理
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>时间字符串格式化处理</title>
</head>
<body>
<script>
/*
* formatTime:时间字符串的格式化处理
* @params
* templete:[string] 我们最后期望获取日期格式的模板
* 模板规则:{0}->年 {1~5}->月日时分秒
* @return
* [string]格式化后的时间字符串
* 2019/08/13
*/
//1.方案一:formatTime
String.prototype.formatTime = function formatTime(template) {
// 1.根据操作的时间字符串获取年月日小时分钟秒等信息
let arr = this.match(/\d+/g).map(item => {
return item.length < 2 ? '0' + item : item;
});
// 2.解析格式化的模板,找到对应的时间,替换模板中的内容
template = template || '{0}年{1}月{2}日 {3}时{4}分{5}秒';
return template.replace(/\{(\d+)\}/g, (_, group) => {
return arr[group] || "00";
});
};
let time = "2019-8-13 16:51:3";
console.log(time.formatTime());
console.log(time.formatTime("{0}年{1}月{2}日"));
console.log(time.formatTime("{1}-{2} {3}:{4}"));
time = "2019/8/13";
console.log(time.formatTime());
console.log(time.formatTime("{0}年{1}月{2}日"));
console.log(time.formatTime("{1}-{2} {3}:{4}"));
//=>服务器获取的
// "2019-8-13 16:51:3"
// "2019/8/13 16:51:3"
// "2019/8/13"
//=>想要转变为的格式
// "08月13日 16时51分"
// "2019年08月13日"
// "2019年08月13日 16时51分03秒"
</script>
</body>
</html>
- 2.match
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>时间字符串格式化处理</title>
</head>
<body>
<script>
//2.方案二:match
let time = "2020-4-8";
//=>变为"2020年04月08日"
let arr = time.match(/\d+/g);
arr = arr.map(item => item.length < 2 ? '0' + item : item);
time = `${arr[0]}年${arr[1]}月${arr[2]}日`;
console.log(time); //=>"2020年04月08日"
</script>
</body>
</html>
- 3.match正则处理方式
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>时间字符串格式化处理</title>
</head>
<body>
<script>
//3.方案三
let time = "2020-4-8";
let arr = time.match(/\d+/g)
.map(item => item.length < 2 ? '0' + item : item);
//arr=['2020','04','08']
let template = '{0}年{1}月{2}日';
// 思路:获取 {0}和0 ,基于索引0到arr中获取"2020",把得到的2020替换{0} =>{0}被替换为arr[0] ...
template = template.replace(/\{(\d+)\}/g, (value, group) => {
// group小分组每一次匹配的结果
// arr[group] 基于小分组捕获的索引到数组中找到对应的项
return arr[group]; //=>返回啥就是把TEMPLETE中大正则本次匹配的结果替换成啥
});
console.log(template);
</script>
</body>
</html>
25.queryURLParams:正则处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>正则处理URL</title>
</head>
<body>
<script>
/*
* queryURLParams:获取URL地址问号和面的参数信息(可能也包含HASH值)
* @params
* @return
* [object]把所有问号参数信息以键值对的方式存储起来并且返回
* by zhufengpeixun on 2019/08/13
*/
String.prototype.queryURLParams = function queryURLParams() {
let obj = {};
this.replace(/([^?=&#]+)=([^?=&#]+)/g, (...[, $1, $2]) => obj[$1] = $2);
this.replace(/#([^?=&#]+)/g, (...[, $1]) => obj['HASH'] = $1);
return obj;
}
let url = "http://www.zhufengpeixun.cn/?lx=1&from=wx#video";
console.log(url.queryURLParams());
//=>{lx:1,from:'wx',HASH:'video'}
</script>
</body>
</html>
26.千分符
- 1.millimeter:实现千分符处理
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>千分符</title>
</head>
<body>
<script>
// millimeter:实现千分符处理
String.prototype.millimeter = function millimeter() {
let str = this.split('').reverse().join('');
str = str.match(/\d{1,3}/g).join(',');
return str.split('').reverse().join('');
};
let str = "2312345638";
str = str.millimeter();
console.log(str); //=>"2,312,345,638"
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>千分符</title>
</head>
<body>
<script>
~function(){
/*
* millimeter:实现大数字的千分符处理
* @params
* @return
* [string]千分符后的字符串
*/
function millimeter() {
return this.replace(/\d{1,3}(?=(\d{3})+$)/g, content => content + ',');
}
["millimeter"].forEach(item => {
String.prototype[item] = eval(item);
});
}();
let num = "15628954"; //=>"15,628,954" 千分符
console.log(num.millimeter());
num = "112345678256874"; //=>"112,345,678,256,874"
console.log(num.millimeter());
</script>
</body>
</html>
27.MATCH VS EXEC
字符串中和正则搭配实现正则捕获的方法 String.prototype
- match
- replace
- split
- 1.在设置全局修饰符G的情况下
- EXEC每一次执只能捕获一个匹配的结果(当前结果中包含大正则和小分组匹配的结果),如果想要捕获全需要执行多次
- MATCH执行一次就能把所有正则匹配的信息捕获到(只有大正则匹配的,并不包含小分组匹配的信息)
let str = "{0}年{1}月{2}日";
let reg = /\{(\d+)\}/g;
console.log(reg.exec(str)); //=>["{0}", "0",...]
// ...
console.log(str.match(reg)); //=>["{0}", "{1}", "{2}"]
- 2.如果不设置G的情况下:都只能捕获到第一个匹配的结果,获取的结果一模一样
let str = "130828199012040617";
let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/;
console.log(reg.exec(str));
//=>["130828199012040617", "130828", "1990", "12", "04", "1",...]
console.log(str.match(reg));
//=>["130828199012040617", "130828", "1990", "12", "04", "1",...]