ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

正则(25)

2021-09-21 23:03:56  阅读:113  来源: 互联网

标签:25 console log 捕获 正则 str reg


 正则基础

 * 正则:是一个用来处理字符串的规则

 *   1.正则只能用来处理字符串

 *   2.处理一般包含两方面:

 *     A:验证当前字符串是否符合某个规则 “正则匹配”

 *     B:把一个字符串中符合规则的字符获取到 “正则捕获”

 *

 * 学习正则其实就是在学习如何编写规则,每一个正则都是由修饰“元字符”、“符”两部分组成

//=>1.创建正则的两种方式
// let reg1 = /^\d+$/g;//=>字面量方式
// let reg2 = new RegExp("^\\d+$", "g");//=>构造函数方式

//=>2.正则两个斜杠之间包起来的都是“元字符”,斜杠后面出现的都是“修饰符”
let reg = /^\d+$/g;

 * 常用的修饰符

 *   i:ignoreCase 忽略大写小匹配

 *   m:multiline 多行匹配

 *   g:global 全局匹配

 * 常用的元字符

 *   [特殊元字符]

 *     \d  0~9之间的一个数字

 *     \D  非0~9之间的任意字符

 *     \w  “数字、字母、下划线”中的任意一个 =>/[0-9a-zA-Z_]/等价于\w

 *     \s  匹配任意一个空白字符(包括\t制表符[TAB键四个空格])

 *     \b  匹配边界符  'zhu'(z左边和u右边就是边界)  'zhu-feng'(z左边、u右边、f左边、g右边是边界)

 *     \n  匹配一个换行符

 *     \  转义字符(把一个普通字符转义为特殊的字符,例如:\d,把有特殊含义的转换为普通意思,例如:\. 此处的点就不是任意字符,而是一个小数点)

 *     . 不仅仅是小数点,代表除了\n以外的任意字符

 *     ^  以某个元字符开头

 *     $  以某个元字符结尾

 *     x|y  x或者y中的任意一个(a|z...)

 *     [xyz] x或者y或者z中的任意一个

 *     [^xyz] 除了x\y\z以外的任意字符

 *     [a-z] 获取a-z中的任意一个字符([0-9] 等价于\d ...)

 *     [^a-z] 除了a-z的任意字符

 *     ()  正则分组

 *     (?:) 当前分组只匹配不捕获

 *     (?=) 正向预查

 *     (?!) 负向预查

 *     ...

 *

 *   [量词元字符:让其左边的元字符出现多少次]

 *     * 出现零到多次

 *     ? 出现零到一次

 *     + 出现一到多次

 *     {n} 出现N次

 *     {n,} 出现N到多次

 *     {n,m} 出现N到M次

 *

 *   [普通元字符]

 *     只要在正则中出现的元字符(在基于字面方式创建),除了特殊和有量词意义的以外,其余的都是普通元字符

中括号的一点特殊细节

 * 中括号的一些细节

 *   [xyz]

 *   [^xyz]

 *   [a-z]

 *   [^a-z]

 *

 * 1.中括号中出现的元字符一般都是代表本身含义的

 * 2.中括号中出现的两位数,不是两位数,而是两个数字中的任意一个

// let reg = /^.+$/;//=>一个正则设置了^和$,那么代表的含义其实就是只能是xxx
// console.log(reg.test('n'));//=>true
// console.log(reg.test('1'));//=>true
// console.log(reg.test('nn'));//=>true
// console.log(reg.test('\n'));//=>false

// let reg = /^[.]+$/;
// console.log(reg.test('n'));//=>false
// console.log(reg.test('1'));//=>false
// console.log(reg.test('nn'));//=>false
// console.log(reg.test('\n'));//=>false
// console.log(reg.test('...'));//=>true

// let reg = /^[\d]+$/; //=>\d在这里依然是0~9中的一个数字
// console.log(reg.test('0'));//=>true
// console.log(reg.test('d'));//=>false

// let reg = /^[18]$/;//=>不加^和$代表字符串中只要包含xxx即可
// console.log(reg.test('18'));//=>false
// console.log(reg.test('1'));//=>true
// console.log(reg.test('8'));//=>true

// let reg = /^[12-65]$/;
// console.log(reg.test('13'));//=>false 不是12~65
// console.log(reg.test('7'));//=>false  这个正则的意思是 1或者2~6或者5
// console.log(reg.test('2'));//=>true
//小案例
//年龄:18~65之间
/*
 * 18~19  1[89]
 * 20~59  [2-5]\d
 * 60~65  6[0-5]
 */
// let reg = /^((1[89])|([2-5]\d)|(6[0-5]))$/;

//=>需求:编写一个规则,匹配 "[object AAA]"
// let reg = /^\[object .+\]$/;
// console.log(reg.test('[object AAA]'));//=>true

分组的三个作用

 * 分组的作用

 *   1.改变的默认的优先级

 *   2.分组捕获

 *   3.分组引用

// let reg = /^18|19$/;
// console.log(reg.test('18'));//=>true
// console.log(reg.test('19'));//=>true
// console.log(reg.test('1819'));//=>true
// console.log(reg.test('189'));//=>true
// console.log(reg.test('181'));//=>true
// console.log(reg.test('819'));//=>true
// console.log(reg.test('119'));//=>true

// reg = /^(18|19)$/;
// console.log(reg.test('18'));//=>true
// console.log(reg.test('19'));//=>true
// console.log(reg.test('1819'));//=>false
// console.log(reg.test('189'));//=>false
// console.log(reg.test('181'));//=>false
// console.log(reg.test('819'));//=>false
// console.log(reg.test('119'));//=>false
//正则分组引用
// let reg = /^([a-z])([a-z])\2\1$/;//=>正则中出现的\1代表和第一个分组出现一模一样的内容...
// console.log(reg.test('oppo'));//=>true
// console.log(reg.test('poop'));//=>true
//=>编写一个正则匹配身份证号码
// let reg = /^\d{17}(\d|X)$/;//=>简单:只能匹配是否符合格式,不能提取出身份证中的一些信息
// '130828199012040617'
//=>130828 地域
//=>19901204 出生年月
//=>0617 倒数第二位:奇数=男  偶数=女

let reg = /^(\d{6})(\d{4})(\d{2})(\d{2})\d{2}(\d)(?:\d|X)$/;
console.log(reg.exec('130828199012040617'));//=>EXEC实现的是正则捕获,获取的结果是一个数组,如果不匹配获取的结果是null,捕获的时候不仅把大正则匹配的信息捕获到,而且每一个小分组中的内容也捕获到了(分组捕获) : ["130828199012040617", "130828", "1990", "12", "04", "1", index: 0, input: "130828199012040617"]

* 正则捕获使用的是正则中的EXEC方法
 *   1.如果可以匹配获取的结果是一个数组,如果不能匹配获取的结果是NULL
 *   2.如果我们只在匹配的时候,想要获取大正则中部分信息,我们可以把这部分使用小括号包起来,形成一个分组,这样在捕获的时候,不仅可以把大正匹配的信息捕获到,而且还单独的把小分组匹配的部分信息也捕获到了(分组捕获)
 *   3.有时候写小分组不是为了捕获信息,只是为了改变优先级或者进行分组引用,此时我们可以在分组的前面加上“?:”,代表只去匹配,但是不把这个分组内容捕获

常用的正则表达式

//有效数字
/*
 *  分析规则:
 *    1.可以出现+/-号:可以没有,也可以有一个
 *    2.整数 0 12 9 : 一位或者多位数字,一位0~9,多位数字不能以0开头
 *    3.小数部分:可能有可能没有,有小数点后面至少要跟一位数字
 */
let reg = /^[+-]?(\d|([1-9]\d+))(\.\d+)?$/;
/*
 * 电话(手机)号码
 *   1. 11位数字
 *   2. 以1开头
 */
let reg = /^1\d{10}$/;
/*
 * 中文姓名
 *   1. 中文汉字  [\u4E00-\u9FA5]
 *   2. 尼古拉斯·赵四
 */
let reg = /^[\u4E00-\u9FA5]{2,}(·[\u4E00-\u9FA5]{2,})?$/;
/*
 * 邮箱
 *   xxxx@xxx.xx.xx
 *
 *  第一部分:数字、字母、下划线、-、.,但是-和.不能作为开头,不能连续出现-或者.
 *
 *  第二部分:xxx.xx.xx  xxx.xx  xxx.xx.xx.xx  xxx-xxx-xx.xx.xx
 *
 */
//=>/^\w+((-\w+)|(\.\w+))*@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/

let reg = /^\w+([-.]\w+)*@[A-Za-z0-9]+([-.][A-Za-z0-9]+)*(\.[A-Za-z0-9]+)$/;

正则捕获的懒惰性和解决方案

 * 正则捕获:把一个字符串中和正则匹配的部分获取到
 *   [正则]
 *     exec
 *     test
 *
 *   [字符串]
 *     replace
 *     split
 *     match
 *     ...

let str = 'zhufeng2018peixun2019';
let reg = /\d+/;

console.log(reg.exec('zhufengpeixun'));//=>null
console.log(reg.exec(str));//=>['2018',index:7,input:...]

 * 基于EXEC可以实现正则的捕获

 *   1.如果当前正则和字符串不匹配,捕获的结果是NULL

 *   2.如果匹配,捕获的结果是一个数组

 *     0:大正则捕获的内容

 *     index:正则捕获的起始索引

 *     input:原始操作的字符串

 *     ...

 *   3.执行一次EXEC只能捕获到第一个和正则匹配的内容,其余匹配的内容还没有捕获到,而且更恶心的是,我傻傻的执行多次,然而并没啥卵用 =>“正则的捕获有懒惰性”:只能捕获到第一个匹配的内容,剩余的默认捕获不到

//=>LAST-INDEX不变导致了正则捕获的懒惰性
// console.log(reg.lastIndex);//=>0 正则捕获时候,下一次在字符串中开始查找的索引
// console.log(reg.exec(str));//=>['2018']
// console.log(reg.lastIndex);//=>0
// console.log(reg.exec(str));//=>['2018']

//=>即使我们手动修改了LAST-INDEX,然而还是没啥卵用
// console.log(reg.exec(str));//=>['2018']
// reg.lastIndex = 11;
// console.log(reg.lastIndex);//=>11
// console.log(reg.exec(str));//=>['2018']

//=>解决正则捕获的懒惰性,我们需要加全局修饰符G(这个是唯一的方案,而且不加G不管用什么办法捕获,也都不能把全部匹配的捕获到)
// let str = 'zhufeng2018peixun2019';
// let reg = /\d+/g;
// console.log(reg.lastIndex);//=>0
// console.log(reg.exec(str));//=>['2018']
// console.log(reg.lastIndex);//=>11
// console.log(reg.exec(str));//=>['2019']
// console.log(reg.lastIndex);//=>21
// console.log(reg.exec(str));//=>null
// console.log(reg.lastIndex);//=>0
// console.log(reg.exec(str));//=>['2018']
let str = 'zhufeng2018peixun2019yangfan2020qihang2021';
let reg = /\d+/g;
RegExp.prototype.myExecAll = function (str) {
    //=>this:reg 当前操作的正则
    //=>str:我们要捕获的字符串
    //=>执行EXEC开始捕获,具体捕获多少次不定,但是一直到捕获不到内容(NULL)为止,期间把捕获到的内容存储到数组中即可
    //=>为了防止出现死循环:我们检测一下正则是否加G,没有加G只把第一次捕获的结果返回即可
    if (!this.global) {
        return this.exec(str);
    }
    let result = [],
        valAry = this.exec(str);
    while (valAry) {//=>this.lastIndex < str.length
        result.push(valAry[0]);//=>把每一次正则捕获到的结果第一项(具体捕获的内容)存储到容器中
        valAry = this.exec(str);
    }
    return result;
};
console.log(reg.myExecAll(str));
console.log(str.match(reg));//=>MATCH实现了我们自己编写的EXEC-ALL处理的事情,正则不加G返回第一个匹配的即可,加了G,把所有匹配的内容都捕获到,最后统一存储到一个数组中返回

正则捕获的贪婪性和分组捕获

// let str = 'zhufeng{2018}peixun{2019}yangfan{2020}qihang{2021}';
// let reg = /\{(\d+)\}/g;//=>大括号有特殊含义:{N}出现的次数

// console.log(reg.exec(str));//=>['{2018}','2018'] 在正则捕获的时候,如果正则中存在分组,捕获的时候不仅仅把大正则匹配到的字符捕获到(数组第一项),而且把小分组匹配的内容也单独抽取出来(数组中的第二项开始就是小分组捕获的内容) =>“分组捕获” ,而/\{(?:\d+)\}/g  ?:是用来阻止分组捕获内容的“只匹配不捕获”

// console.log(str.match(reg));//=>["{2018}", "{2019}", "{2020}", "{2021}"]  MATCH方法也有自己的局限性,在正则设置了G的情况下,基于MATCH捕获的内容只有大正则匹配的,小分组的内容没有单独抽取出来(不设置G的情况下和执行EXEC一样)

//===========================
//=>正则捕获还具备贪婪性:每一次匹配捕获的时候,总是捕获到和正则匹配中最长的内容,例如: '2' 符合 \d+  '2018' 也符合 \d+,但是捕获的是最长的内容 '2018'...
let str = 'zhufeng2018peixun2019';
let reg = /\d+?/g;//=>把问号放到量词元字符后面,代表的就不是出现零次或者一次了,而且取消捕获的贪婪性
console.log(reg.exec(str));//=>['2']

 * ?在正则中的作用
 *   1.量词元字符:出现零次或者一次
 *     /-?/ 让减号出现一次或者不出现
 *
 *   2.取消贪婪性
 *     /\d+?/ 捕获的时候只捕获最短匹配的内容
 *
 *   3.?: 只匹配不捕获
 *
 *   4.?= 正向预查
 *
 *   5.?! 负向预查

更多的捕获方式(REPLACE)

// let str = 'zhufeng2018peixun2019';
// let reg = /\d+/g;
// console.log(reg.test(str));//=>TRUE
// console.log(reg.lastIndex);//=>11 基于TEST进行匹配的时候,如果设置了G,TEST匹配也相当于捕获,修改了LAST-INDEX的值
// console.log(reg.exec(str));//=>['2019']

// let str = 'zhufeng2018';
// let reg = /\d+/g;
// if(reg.test(str)){
//     console.log(reg.exec(str));//=>NULL
// }

// let str = 'zhufeng2018';
// let reg = /\d+/g;
// console.log(reg.exec(str));//=>['2018'] 把REG.LAST-INDEX修改了
// console.log(reg.exec('zhufeng2018peixun2019'));//=>['2019'] 虽然捕获的不是同一个字符串,但是正则是同一个,上一次正则处理的时候修改了它的LAST-INDEX,也会对下一次匹配新的字符串产生影响

// let str = 'zhufeng2018peixun2019';
// let reg = /(\d+)/g;
// console.log(reg.test(str));//=>TRUE
// console.log(RegExp.$1);//=>'2018' //=>把上一次匹配(TEST/EXEC)到的结果获取到,获取的是第一个小分组匹配的内容,大正则匹配的内容无法获取,它是一个全局的值,浏览器中$1只有一个,其它的正则操作也会覆盖这个值,所以这种方式没啥用
// console.log(reg.test(str));//=>TRUE
// console.log(RegExp.$1);//=>'2019'
// console.log(reg.test(str));//=>FALSE
// console.log(RegExp.$1);//=>'2019'
// console.log(reg.test(str));//=>TRUE
// console.log(RegExp.$1);//=>'2018'
/*
 * replace:实现正则捕获的方法(本身是字符串替换)
 */
// let str = 'zhufeng2018zhufeng2019';//=>'zhufeng' => 'zhufengpeixun'

//=>真实项目中很多需求不基于正则是无法替换的
// str = str.replace('zhufeng', 'zhufengpeixun');
// console.log(str);//=>'zhufengpeixun2018zhufeng2019'
// str = str.replace('zhufeng', 'zhufengpeixun');
// console.log(str);//=>'zhufengpeixunpeixun2018zhufeng2019'

// str = str.replace(/zhufeng/g, 'zhufengpeixun');
// console.log(str);//=>'zhufengpeixun2018zhufengpeixun2019'

//==============REPLACE原理
// let str = 'zhufeng{val:2018}zhufeng{val:2019}',
//     reg = /\{val:(\d+)\}/g;
// str = str.replace(reg, '@');//=>用REG正则和STR字符串进行匹配,匹配几次就替换几次,每一次都是把当前“大正则”匹配的结果用第二个传递的字符串替换掉了
// console.log(str); //=>'zhufeng@zhufeng@'

// str = str.replace(reg, '$1');//=>$1不是拿这个字符串替换掉大正则匹配的内容,此处的$1代表第一个分组匹配的内容,等价于 RegExp.$1
// console.log(str);//=>'zhufeng2018zhufeng2019'

/*
 * 1. REG 和 STR 匹配多少次,函数就被触发执行对少次,而且传递了一些参数信息值
 * 2. 每一次ARG中存储的信息,和执行EXEC捕获的信息相似(内置原理:每一次正则匹配到结果,都把函数执行,然后基于EXEC把本次匹配的信息捕获到,然后把捕获的信息传递给这个函数)
 * 3. 每一次函数中返回的是啥,就把当前大正则匹配的内容替换成啥
 */
// str = str.replace(reg, (...arg) => {
//     console.log(arg);
//     return 'AA';
// });
// console.log(str);//=>zhufengAAzhufengAA

小案例处理时间字符串格式化

//=>时间字符串格式化
// "2018/4/30 17:50:23"  => "04-30 17:50"

//=>简单处理
// let str = "2018/4/30 17:50:23",
//     ary = str.split(/(?:\/| |:)/g);
// // console.log(ary);//=>["2018", "4", "30", "17", "50", "23"]
// let [, month, day, hours, minutes] = ary,
//     result = `${month}-${day} ${hours}:${minutes}`;
// console.log(result);

// let str = "2018/4/30 17:50:23";
// //1.获取时间字符串中的所有数字 (SPLIT)
// let ary = str.match(/\d+/g).map(item => {
//     return item < 10 ? '0' + item : item;
// });//=>MAP相对于FOR-EACH来讲多了返回值,函数中RETURN的是啥,就是把当前数组中迭代的这一项替换成啥
// // console.log(ary);//=>["2018", "04", "30", "17", "50", "23"]

//2.指定最后想要的时间格式,我们基于这个数组中的内容,帮你拼接好即可
// let template = '{0}年{1}月{2}日 {3}时{4}分{5}秒';
// //=>{0} / 0  =>'2018' ARY[0]
// //=>{1} / 1  =>'04' ARY[1]
// //=>...
// template = template.replace(/\{(\d)\}/g, (...arg) => {
//     let [, index] = arg;//=>index:每一次正则匹配小分组捕获的结果(也就是那个数字)
//     return ary[index];
// });
// console.log(template);

//=>时间字符串格式化
String.prototype.myFormatTime = function myFormatTime(template = '{0}年{1}月{2}日 {3}时{4}分{5}秒') {
    let ary = this.match(/\d+/g).map(item => (item < 10 ? '0' + item : item));
    return template.replace(/\{(\d)\}/g, (...[, index]) => ary[index] || '00');
};

let str = "2018-4-30";
console.log(str.myFormatTime('{1}-{2} {3}:{4}'));

标签:25,console,log,捕获,正则,str,reg
来源: https://blog.csdn.net/qq_45738592/article/details/120399234

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有