系统认识JavaScript正则表达式

作者: 45a7192a6d1f | 来源:发表于2019-08-03 13:00 被阅读25次

    一、正则表达式简介

    1、什么是正则表达式

    正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。

    简单的说,就是按照某种规则去匹配符合条件的字符串。

    2、可视化正则表达式工具

    Regexper:https://regexper.com/

    二、RegExp对象

    实例化RegExp的两种方式。

    两种方式定义RegExp对象。

    1、字面量

    let reg = /[a-z]{3}/gmi;
    let reg = /[a-z]{3}/g;
    let reg = /[a-z]{3}/m;
    let reg = /[a-z]{3}/i;
    

    标志

    • g global 代表全局搜索。如果不添加,搜索到第一个匹配停止。
    • m Multi-Line 代表多行搜索。
    • i ignore case 代表大小写不敏感,默认大小写敏感。

    2、构造函数

    let reg = new RegExp('\\bis\\b', 'g');
    

    因为JavaScript字符串中\属于特殊字符,需要转义。

    很多时候跟着书和网站查找资料学习,会发现没有目标,学了很多却不知道自己到底能够做出什么成绩。要有一个清晰的职业学习规划,学习过程中会遇到很多问题,这里推荐一下我的前端学习交流群:767273102,里面都是学习前端的从最基础的HTML+CSS+JavaScript。jQuery,Ajax,node,angular等到移动端HTML5的项目实战的资料都有整理,送给每一位前端小伙伴。最新技术,与企业需求同步。好友都在里面学习交流,每天都会有大牛定时讲解前端技术!

    三、元字符

    把元字符当作转义字符。

    正则表达式有两种基本字符类型组成。

    • 原义文本字符
    • 元字符

    1、原义文本字符

    表示原本意义上是什么字符,就是什么字符。

    2、元字符

    是在正则表达式中有特殊含义的非字母字符。
    * + ? $ ^ . | \ ( ) { } [ ]

    字符 含义
    \t 水平制表符
    \v 垂直制表符
    \n 换行符
    \r 回车符
    \0 空字符
    \f 换页符
    \cX 控制字符,与X对应的控制字符(Ctrl + X)

    类似于转义字符。

    四、字符类

    表示符合某种特性的字符类别。

    使用元字符[]可以构建一个简单的类。
    所谓类是指符合某些特性的对象,一个泛指,而不是某个字符。

    例子

    表达式[abc]把字符abc归为一类,表达式可以匹配这一类中的任意一个字符。

    // replace() 方法用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串。
    'a1b2c3d4e5'.replace(/[abc]/g, '0');  //010203d4e5
    

    字符类取反

    我们想要替换不是abc中任意一个字符的字符。

    // 元字符 ^ 创建一个 反向类/负向类
    'abcdefg'.replace(/[^abc]/g, '0');  //abc0000
    

    五、范围类

    匹配这一个范围内的字符。

    如果我们想要匹配数字0-9,那么我们可能会这样写[0123456789]
    如果我们想要匹配26个字母,那么我们可能会这样写[abcdefghijklmnopqrstuvwxyz]
    这样略显麻烦,所以才会有范围类。

    例子

    // 替换所有数字
    'a1c2d3e4f5'.replace(/[0-9]/g, 'x');  //axcxdxexfx
    // 替换所有小写字母
    'a1c2d3e4f5'.replace(/[a-z]/g, 'x');  //x1x2x3x4x5
    // []组成的类内部是可以连写的。替换所有大小写字母
    'a1C2d3E4f5G6'.replace(/[a-zA-Z]/g, '*');  //*1*2*3*4*5*6
    

    疑问

    如果我想替换数字,并且连带-符号也一起替换呢?

    // 替换所有数字和横杠
    '2018-5-21'.replace(/[0-9-]/g, '*');  //*********
    

    六、预定义类

    一些已经定义的类,可以直接使用。

    字符 等价类 含义
    . [^\r\n] 除了回车、换行之外的所有字符
    \d [0-9] 数字字符
    \D [^0-9] 非数字字符
    \s [\t\n\x0B\r] 空白符
    \S [^\t\n\x0B\r] 非空白符
    \w [a-zA-Z_0-9] 单词字符(字母、数字、下划线)
    \W [^a-zA-Z_0-9] 非单词字符

    例子

    替换一个 ab + 数字 + 任意字符 的字符串

    // 写法1
    'ab0c'.replace(/ab[0-9][^\r\n]/g, 'TangJinJian');  //TangJianJian
    // 写法2
    'ab0c'.replace(/ab\d./g, 'TangJinJian');  //TangJianJian
    

    七、单词边界

    字符 含义
    ^ 以xxx开始(不在中括号内时的含义)
    $ 以xxx结束
    \b 单词边界
    \B 非单词边界

    例子

    我想替换的字符串,属于那种只在开头出现的。

    'YuYan is a boy, YuYan'.replace(/^YuYan/g, 'TangJinJian');  //TangJinJian is a boy, YuYan
    

    我想替换的字符串,属于那种只在结尾出现的。

    'YuYan is a boy, YuYan'.replace(/YuYan$/g, 'TangJinJian');  //YuYan is a boy, TangJinJian
    

    单词边界例子。

    // 替换所有is为0
    'This is a man'.replace(/is/g, '0');  //Th0 0 a man
    // 替换所有is前面带有单词边界的字符串
    'This is a man'.replace(/\bis/g, '0');  //This 0 a man
    // 替换所有is前面没有单词边界的字符串
    'This is a man'.replace(/\Bis\b/g, '0');  //Th0 is a man
    

    八、量词

    用来处理连续出现的字符串。

    字符 含义
    ? 出现零次或一次(最多出现一次)
    + 出现一次或多次(至少出现一次)
    * 出现零次或多次(任意次)
    {n} 出现n次
    {n,m} 出现n到m次
    {n,} 至少出现n次

    我想替换字符串中连续出现10次的数字为*

    '1234567890abcd'.replace(/\d{10}/, '*');  //*abcd
    

    我想替换字符串中的QQ号码。

    '我的QQ是:10000'.replace(/[1-9][0-9]{4,}/, '19216811');  //我的QQ是:19216811
    

    九、贪婪模式

    尽可能多的匹配。

    有这样的一种场景下的正则表达式,/\d{3,6}/该替换3个数字还是6个数字呢,4、5个数字?

    // 贪婪模式会尽可能的往多的方面去匹配
    '123456789'.replace(/\d{3,6}/, 'x');  //x789
    '123456789'.replace(/\d+/, 'x');  //x
    '123456789'.replace(/\d{3,}/, 'x');  //x
    

    十、非贪婪模式

    尽可能少的匹配。

    如果我们想要最低限度的替换呢?

    // 非贪婪模式使用 ? 尽可能的往少的方面去匹配
    '12345678'.replace(/\d{3,6}?/g, 'x');  //xx78
    '123456789'.replace(/\d{3,6}?/g, 'x');  //xxx
    

    因为有g标志,会匹配这段字符串里所有符合规则的字符串。
    第一个规则/\d{3,6}?/g12345678中有两个符合条件的字符串,是123456。所以替换结果是xx78
    第二个规则/\d{3,6}?/g123456789中有三个符合条件的字符串,是123456789。所以替换结果是xxx

    十一、分组

    括号里的一些规则,分为一组。

    我想替换连续出现3次的字母数字

    //没有分组的情况下,后面的量词,只是表示匹配3次数字。
    'a1b2d3c4'.replace(/[a-z]\d{3}/g, '*');  //a1b2d3c4
    //有分组的情况下,分组后面的量词,表示符合这个分组里规则的字符串,匹配3次。
    'a1b2d3c4'.replace(/([a-z]\d){3}/g, '*');  //*c4
    

    1、或

    分组里有两种规则,只要满足其中一种即可匹配。

    //我想把ijaxxy和ijcdxy都替换成*
    'ijabxyijcdxy'.replace(/ij(ab|cd)xy/g, '*');  //**
    

    2、反向引用

    可以把分组视为变量,来引用。

    //我想把改变年月日之间的分隔符
    '2018-5-22'.replace(/(\d{4})-(\d{1,2})-(\d{1,2})/g, '$1/$2/$3');  //2018/5/22
    //我想替换日期,并且更改顺序
    '2018-5-22'.replace(/(\d{4})-(\d{1,2})-(\d{1,2})/g, '$2/$3/$1');  //5/22/2018
    

    3、忽略分组

    忽略掉分组,不捕获分组,只需要在分组内加上?:

    // 忽略掉匹配年的分组后,匹配月的分组变成了$1,日的分组变成了$2
    '2018-5-22'.replace(/(?:\d{4})-(\d{1,2})-(\d{1,2})/g, '$1/$2/$3');  //5/22/$3
    

    十二、前瞻

    正则表达式从文本头部向尾部开始解析,文本尾部方向,称为“前”。
    前瞻就是在正在表达式匹配到规则的时候,向前检查是否符合断言,后顾/后瞻方向相反。
    JavaScript不支持后顾。
    符合和不符合特定断言称为肯定/正向匹配和否定/负向匹配。

    名称 正则 含义
    正向前瞻 exp(?=assert)
    负向前瞻 exp(?!assert)
    正向后顾 exp(?<=assert) JavaScript不支持
    负向后顾 exp(?<!assert) JavaScript不支持

    例子

    有这样一个单词字符+数字格式的字符串,只要满足这种格式,就把其中的单词字符替换掉。

    'a1b2ccdde3'.replace(/\w(?=\d)/g, '*');  //*1*2ccdd*3
    

    有这样一个单词字符+非数字格式的字符串,只要满足这种格式,就把前面的单词字符替换掉。

    'a1b2ccdde3'.replace(/\w(?!\d)/g, '*');  //a*b*****e*
    

    十三、RegExp对象属性

    global是否全文搜索,默认false
    ignore case是否大小写敏感,默认是false
    multiline多行搜索,默认值是false
    lastIndex是当前表达式匹配内容的最后一个字符的下一个位置。
    source正则表达式的文本字符串。

    let reg1 = /\w/;
    let reg2 = /\w/gim;
    
    reg1.global;  //false
    reg1.ignoreCase;  //false
    reg1.multiline;  //false
    
    reg2.global;  //true
    reg2.ignoreCase;  //true
    reg2.multiline;  //true
    

    十四、RegExp对象方法

    1、RegExp.prototype.test()

    用来查看正则表达式与指定的字符串是否匹配。返回truefalse

    let reg1 = /\w/;
    reg1.test('a');  //true
    reg1.test('*');  //false
    

    加上g标志之后,会有些区别。

    let reg1 = /\w/g;
    // 第一遍
    reg1.test('ab');  //true
    // 第二遍
    reg1.test('ab');  //true
    // 第三遍
    reg1.test('ab');  //false
    // 第四遍
    reg1.test('ab');  //true
    // 第五遍
    reg1.test('ab');  //true
    // 第六遍
    reg1.test('ab');  //false
    

    实际上这是因为RegExp.lastIndex。每次匹配到之后,lasgIndex会改变。
    lastIndex是正则表达式的一个可读可写的整型属性,用来指定下一次匹配的起始索引。

    let reg = /\w/g;
    // 每次匹配到,就会把lastIndex指向匹配到的字符串后一个字符的索引。
    while(reg.test('ab')) {
        console.log(reg.lastIndex);
    }
    // 1
    // 2
    

    reg.lastIndex初始时为0,第一个次匹配到a的时候,reg.lastIndex1。第二次匹配到b的时候,reg.lastIndex2

    相关文章

      网友评论

        本文标题:系统认识JavaScript正则表达式

        本文链接:https://www.haomeiwen.com/subject/oixmkctx.html