美文网首页
正则大全

正则大全

作者: 我是上帝可爱多 | 来源:发表于2017-07-21 11:55 被阅读20次

    我们在开发中经常会用到正则匹配,但是里面内容庞大实在难以记清,今天我们就来梳理一下正则知识,并在最后送上一些经常用到的匹配方案,毕竟自己也是很害怕这一块的。
    1.replace
    关于replace的用法,其实很多,我们会仔细讲解。

    var re = /apples/gi;
    var str = "Apples are round, and apples are juicy.";
    var newstr = str.replace(re, "oranges");
    
    // oranges are round, and oranges are juicy.
    console.log(newstr);
    
    

    最基本的用法,g全局匹配,i忽略大小写。

    var re = /(\w+)\s(\w+)/;
    var str = "John Smith";
    var newstr = str.replace(re, "$2, $1");
    // Smith, John
    console.log(newstr);
    交换了2个单词的位置
    
    var re = /(\w+)\s(\w+)/;
    var str = "John Smith";
    var newstr = str.replace(re, "$2, $1,$&");
    // Smith, John,John Smith
    

    \s是匹配空格,$&是匹配的子串,$1,$2分别字匹配项。
    再来看一个

    function replacer(match, p1, p2, p3, offset, string) {
      // p1 is nondigits, p2 digits, and p3 non-alphanumerics
      return [p1, p2, p3].join(' - ');
    }
    var newString = 'abc12345#$*%'.replace(/([^\d]*)(\d*)([^\w]*)/, replacer);
    

    这里我们一目了然了把,看replcaer里面的参数就知道了。

    我想问一下大家知道$&和replacer函数里面最后一个参数string有啥区别
    其实我刚刚做了个实验,但是发现有问题,就先不说了,等下会有结论再讲吧。

    function f2c(x)
    {
      function convert(str, p1, offset, s)
      {
        return ((p1-32) * 5/9) + "C";
      }
      var s = String(x);
      var test = /(\d+(\.\d*)?)F/g;
      return s.replace(test, convert);
    }
    

    函数传入一个x,将其从华氏温度转成摄氏度。

    2.exec
    exec是正则里面会比较频繁用到的,想想jquery的源码,里面充斥的这样的匹配。

    var str = "javascript html css 555";
    console.log(/(html) (css) (\d*)/.exec(str)); // ["html", index: 11, input: "javascript html css"]
    output:
     ["html css 555", "html", "css", "555", index: 11, input: "javascript html css 555"]
    

    可以看出来exec方法,会返回一个数组,第一个元素是符合匹配的字符串合集,第二个到第n个是表达式的子项,index是符合首个匹配的索引,input是源字符串。

    var x = " a.xxx.com b.xxx.com c.xxx.com";
    var re = /\s?(.*?).xxx.com/g;
    while( tempR = re.exec(x))
    {
     console.log(tempR);
    }
    output:
    [" a.xxx.com", "a", index: 0, input: " a.xxx.com b.xxx.com c.xxx.com"]
    [" b.xxx.com", "b", index: 10, input: " a.xxx.com b.xxx.com c.xxx.com"]
    [" c.xxx.com", "c", index: 20, input: " a.xxx.com b.xxx.com c.xxx.com"]
    //一般用于循环,将所有的匹配都输出出来,注意(.*?)匹配任何东西。
    

    再来最后一个例子

    var myRe = /ab*/g;
    var str = 'abbcdefabh';
    var myArray;
    while ((myArray = myRe.exec(str)) !== null) {
      var msg = 'Found ' + myArray[0] + '. ';
      msg += 'Next match starts at ' + myRe.lastIndex;
      console.log(msg);
    }
    output:
    Found abb. Next match starts at 3
    Found ab. Next match starts at 9
    

    注意lastIndex是指匹配的末项索引。

    3.search
    这个没啥其他扩展,咱们一笔带过

    var str = "hello world,hello world";
    // 返回匹配到的第一个位置
    console.log(str.search(/hello/)); // 0
    // search方法不执行全局匹配,它将忽略标志g,同时它也没有regexp对象的lastIndex的属性,且总是从字符串开始位置进行查找,总是返回的是stringObject匹配的第一个位置。
    console.log(str.search(/hello/g)); //0
    console.log(str.search(/world/)); // 6
    
    

    search方法都是从第一个位置开始查找,并且没有全局g的标志。

    4.match
    初级用法和exec差不多,但是他全局匹配可以返回一个所有符合正则的数组。

    var str = "hello world";
    // 返回的数组内有三个元素,第一个元素的存放的是匹配的文本,还有二个对象属性;
    index属性表明的是匹配文本的起始字符在stringObject中的位置;input属性声明的是
    对stringObject对象的引用;
    console.log(str.match("hello")); // ["hello", index: 0, input: "hello world"]
    
    var re = new RegExp('([0-9]+)-([0-9]+)-([0-9]+)');
    var str = '2016-01-02';
    var result = str.match(re); 
    console.log(result.)); // [2016,01,02]
    

    用了全局方法后会得到一个所有符合匹配的数组。

    基本用法咱们讲解完毕,我们来看一下高阶用法。
    1.贪婪模式和懒惰模式
    相信大家对这个已经有所耳闻了,那我们来看到底是啥。

    var txt = '<a href=”http://google.com”>谷歌</a><a href=”http://baidu.com”>百度</a>'
    var re1 = /\<a (.*?)\<\/a\>/g; //懒惰模式,尽可能少的匹配
    
    console.log(re1.exec(txt)); 
    //["<a href=”http://google.com”>谷歌</a>", "href=”http://google.com”>谷歌"]
    
    console.log(re1.exec(txt));
    //["<a href=”http://baidu.com”>百度</a>", "href=”http://baidu.com”>百度"]
    这个是懒惰模式,跟我们之前讲的exec并没有啥区别,接着看下面这个。
    
    var re2 = /\<a (.*)\<\/a\>/g; //贪婪模式,尽可能多的匹配, 区别在不加问号
    console.log(re2.exec(txt));
    //["<a href=”http://google.com”>谷歌</a><a href=”http://baidu.com”>百度</a>", 
    //"href=”http://google.com”>谷歌</a><a href=”http://baidu.com”>百度"]
    console.log(re2.exec(txt));
    //null
    相信大家已经看粗什么端倪来了,贪婪模式会把a标签中间所有的都检索到,所以到值exec执行一次
    就没有下文了。
    

    2.捕获分组和非捕获分组
    看起来却是一脸蒙蔽,我们简短说一下吧,毕竟这个属于很少用的。

    var str = "a1***ab1cd2***c2";  
    var reg1 = /((ab)+\d+)((cd)+\d+)/i; 
    var reg2 = /((?:ab)+\d+)((?:cd)+\d+)/i; 
    console.log(str.match(reg1));
    output:
    ["ab1cd2", "ab1", "ab", "cd2", "cd", index: 5, input: "a1***ab1cd2***c2"]
    我们发现第二层括号里面的居然也北大引出来了,我们其实只想要外层的匹配
    console.log(str.match(reg2));
    output:
    ["ab1cd2", "ab1",  "cd2", index: 5, input: "a1***ab1cd2***c2"]
    
    

    其实捕获和不捕获就是指的匹配想得子项是否被归入到结果中,如果还不够明白请看下面

    var reg = /(?:\d{4})-(\d{2})-(\d{2})/
    var reg1 = /(\d{4})-(\d{2})-(\d{2})/
    var date = '2012-12-21'
    reg.test(date)
    RegExp.$1  
    "12"
    奇怪了第一个匹配的\d{4}明明是2012,为什么会输出12呢
    reg1.test(date)
    RegExp.$1  
    “2012”
    

    反正我已经是领略到了,如果还有疑问可以看mdn开发文档

    3.零宽断言
    零宽断言就是下结论,例如ab,正则:a(?=b),匹配a并且向右看是b,得到的结果是a,断言不会在匹配的内容当中,如果是a(?=c),则匹配不到任何内容,因为匹配a以后向右看并不是c。另外,零宽断言分两种:前瞻(Lookahead)和后顾(Lookbehind);但JavaScript只支持前瞻。

    // 获取字符串中以ing结尾的单词的前半部分
    var str = 'I love dancing but he likes playing';
    var pattern = /\b\w+(?=ing\b)/g;
    var ans = str.match(pattern);
    console.log(ans);
    output:
    [danc,play]
    
    // 获取第五位不是i的单词的前四位
    var s = 'I love dancing but he likes singing';
    var pattern = /\b\w{4}(?!i)/g;
    var ans = s.match(pattern);
    console.log(ans); // ["love", "like"]
    

    下面以一个很经典的例子结束本期

    var str = '1234567890'
    '12334565632'.replace(/(\d)(?=(\d{3})+$)/g, "$1,");
    output:
    "12,334,565,632"
    记住要加上g,不然结果是12,334565632
    

    又要结束了,下期会给大家带来前端工具gulp的文章。

    相关文章

      网友评论

          本文标题:正则大全

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