说说正则的那些事

285 阅读5分钟

我胡汉三终于又又又回来了,哈哈哈哈......什么?你说我不着调?不可能的我堂堂Yuhior 怎么可能干不着调的事呢?回顾一下最近的生活和学习,越发觉得每天光用框架啊,什么Vue啊,什么React啊,当然这些我都不会啊,哈哈哈,学习这些感觉力不从心,决心重新学习js,打好自己的基础能力,深知自己这座小平房地基不稳,哪能期盼盖出高楼啊,那最后塌了,不得害死自己啊,所以最近在看书,看红宝书(超级推荐),今天看到正则表达式觉得自己原来哪会什么正则啊,都是临到用了去搜一搜,虽说造轮子和吹飞机有一定区别,但是自己还是应该去深入学习,毕竟自己的才是财富。废话不多说,来看看我对正则的理解,如有不到之处,求大佬们请勿嫌弃我这个小渣渣。开始吧

  • 招式一:元字符匹配

    正则表达式也就是匹配的模式,要么是要去匹配想要的字符,要么是匹配位置 ,但是有木有感觉元字符太多记不住?第一我们先知道匹配模式有3个标志 :

    g:表示全局模式,将被应用于所有的字符串。而非发现第一个匹配项时立即停止;

    i:表示不区分大小写,即在确定匹配项时忽略模式与字符串的大小写;

    m:表示多行模式,即在到达一行的文本末时,继续向下一行进行查找;

    1. 有两种模糊匹配(如果精准匹配,没多大意义,那还不如用直接indexof)

      • 横向模糊(长度不固定) {2,5}

        /ab{2,5}c/

        var regex = /ab{2,5}c/g;
        var string = "abc abbc abbbc abbbbc abbbbbc abbbbbbc";
        console.log(string.match(regex))
        //  ["abbc", "abbbc", "abbbbc", "abbbbbc"]
        
      • 纵向模糊(配到某个字符不确定是特定的字符)[abc]

        /a[123]b/

        var regex  =  /a[bcd]b/g;
        var string = "abb acb adb afb agb";
        console.log(string.match(regex));
        ["abb", "acb", "adb"]
        
    2. 字符组 (很想数组把? 也就是 [ ] 中有一些字符 )

      • 范围表示

        [abc]很短还好说,但是要很长怎么办?不能一个个写把? 那范围表示法就来了

        [123456abcdefgHIJKLMN] => [1-6a-gH-N] 用 连字符 -来省略和简写

        但是要匹配 "a" "-" "z" 任意一个字符怎么办? 可以写成[-az]或者[az-]或者[a-z]

      • 排除字符组

        有一种情况就是纵向模糊匹配,某位字符可以是任何东西,但是就是不能是某个字符,也就是求反

        [^abc]

        当然后边的也有相应的范围表示表示法 [ ^abcdefghijkl] =>[ ^a-l]

      • 常见的简写形式

        \d =>[0-9]  表示一位数字  也就是digit
        \D =>[^0-9] 表示除数字外的任意字符
        \w =>[0-9a-zA-Z]  表示数字、大小写字母和下划线。word 
        \W =>[^0-9a-zA-Z]  表示非单词字符
        \s =>[\t\v\n\r\f] 表示空白符  记忆也就是 space
        \S =>[^\t\v\n\r\f]  非空白符
        . 通配符  除换行符、回车符、行分隔符、段分隔符除外的所有
        匹配任意字符 [^] 
        
    3. 量词 {2,5}

      • 简写形式

        {m,} => 至少出现m次
        {m} => 表示出现m次
        ? =>{0,1},表示出现或者不出现 。记忆: 有么?
        + =>{1,} 表示出现至少一次 。 记忆:加号是追加的意思,得先有一个,然后才考虑从追加
        * =>{0,} 表示出现任意次,有可能不出现,记忆:看天上星星,黑天啊没有,可能是零星几颗,也可能是数不过来
        
      • 贪婪匹配和惰性匹配

        贪婪匹配:他会尽可能多的匹配,反正在能力范围之内,越多越好

        var regex = /\d{2,5}/g;   // 表示数字连续出现2-5次
        var string = "123 1234 12345 123456";
        console.log( string.match(regex) );
        //["123", "1234", "12345", "12345"]
        

        惰性匹配:很懒啊 像我一样,能匹配到俩个就绝不多匹配,量词后面加个问号就能实现惰性匹配,记忆方法:问一问你知足了吗,你很贪婪吗?

        var regex = /\d{2,5}?/g;
        var string = "123 1234 12345 123456";
        console.log( string.match(regex) );
        //["12", "12", "34", "12", "34", "12", "34", "56"]
        
    4. 多选分支 (或者也可以叫 “或” )

      多选模式:展现形式(p1 | p2 | p3 ),其中得p1,p2,p3都是子模式,表示其中任何之一都可以

      var regex = /good|nice/g;
      var string ="good idea, nice try.";
      console.log(string.match(regex));
      //  ["good", "nice"]
      

      *注意 当我们用 /good|goodbye/ ,去匹配“goodbye”时,结果只是good,说明分支结构是惰性得,也就是前边的上了,后边就不会再去尝试了。

      var regex = /good|goodbye/g;
      var string = "goodbye";
      console.log( string.match(regex) );
      // ["good"]   
      
      // 改为
      var regex = /goodbye|good/;
      var string = "goodbye";
      console.log( string.match(regex) );
      // ["goodbye"]   
      
  • 招式二:位置匹配攻略

    正则表达式也就是匹配的模式,要么是要去匹配想要的字符,要么是匹配位置,下面我们就来讲一讲位置匹配吧

    1. 什么是位置

      位置

      也就是两个相邻字符之间的位置,比如图中箭头中的位置

    2. 如何匹配位置

      目前有6个锚字符

      ^ $ \b \B (?=p) (?!p)

      • ^ 脱字符 匹配开头的位置,在多行匹配中匹配行开头 (单行匹配)

        var reg = /^/g;
        var string ="hello";
        console.log(string.replace(reg,"#"));
        // #hello
        
      • $ 美元符号 匹配结尾,在多行匹配中匹配行尾 (单行匹配)

        var reg = /$/g;
        var string ="hello";
        console.log(string.replace(reg,"#"));
        // hello#
        
      • \b 是单词边界,具体就是\w 和\W 之间的位置,也包括\w 和^之间的位置,也包括\w和$之间的位置

        var reg = /\b/g;
        var result = "[JS]Lesson_01.mp4";
        console.log(result.replace(reg,"#"));
        // [#JS#]#Lesson_01#.#mp4#
        

        稍微的解释一波,强调不是狡辩😂😂😂,第一个#是在"["和"J"之间的位置,第二个也就是"S"和"]"之间 ....

      • \B 也就是\b的反义 ,那么这么讲也就好理解了 ,也就是\B是反义非单词边界。例如在字符串中所有的位置中,扣掉\b,剩下的都是\b的。 具体:/w与/w、\W与\W 、\W与$之间的位置,来个例子吧

        var reg = /\B/g;
        var result = "[JS]Lesson_01.mp4";
        console.log(result.replace(reg,"#"));
        // #[J#S]L#e#s#s#o#n#_#0#1.m#p#4
        
      • (?=p) 其中p就是那个上边的子模式(或模式也就是随便一个),即 p前边的位置。比如(?= t ),表示""字符前边的位置

        var reg = /(?=l)/g;
        var result = "[JS]Lesson_01.mp4";
        console.log(result.replace(reg,"#"));
        //he#l#lo
        
      • (?!p) 也就是(?=p)的反面意思

        var reg = /(?!p)/g;
        var result = "hello";
        console.log(result.replace(reg,"#"));
        //#h#e#l#l#o#
        
    3. 位置的特性

    对于位置的理解,我们理解成空字符串。

    比如"hello" 字符串等价于如下形式:

      "hello" == "" + "h" + "" + "e" + "" + "l" + "" + "l" + "" + "o" + "";
    // true
    

    还等价于

      "hello" == "" + "" + "hello";
    // true
    

    所以把 /^hello$/ 写成/^^hello$$$/,是没有问题的

      var reg = /^^hello$$$/;
      var result = "hello";
      console.log(reg.test(result));
      //true
    
    1. 应用分析

    • 写一个不匹配任何东西的正则

      /.^/ : 要求只有一个字符(.代表任意字符),但该字符后边是开头

    • 数字的千位分隔符表示法

    先在最后弄一个逗号

      var reg =  /(?=\d{3}$)/g;
      var result = "12345678";
      console.log(result.replace(reg,","));
      // 12345,678
    

    最后弄出所有逗号,也就是后边的3个数字一组,也就是\d{3}至少出现一次。

      var reg = /(?=(\d{3})+$)/g; //使用量词 +
      var result = "12345678";
      console.log(result.replace(reg,","));
      //12,345,678
    

    但是一旦遇到3的倍数位,那就有问题啦首位肯定也会加一个逗号啦,那就不要匹配开头啦 。那就来一个(?!^);

      var reg = /(?!^)(?=(\d{3})+$)/g; //使用量词 +
      var result = "123456789";
      console.log(result.replace(reg,","));
      //123,456,789
    
  • 招式三见下一篇吧