美文网首页
Javascript中的正则表达式总结与实践

Javascript中的正则表达式总结与实践

作者: Katherine的小世界 | 来源:发表于2017-10-12 19:05 被阅读0次

    正则表达式一直是我的弱项,基本都是避而远之的。这次还是咬咬牙关来看一下学习一下吧。连续看了两天,完全没有了解过正则的我,终于也有点小收获了。

    当然,这些东西的学习,除了看<高级程序设计>,我还主要向这位大神学习了,要看更多的信息还是要学学他的。
    https://juejin.im/post/5965943ff265da6c30653879
    看完之后,我就在这里做总结了。

    3a1479998e2fbad23c66caae2664d5a.png

    一 先做一些实例吧。

    1 将 '?a=4&b=99'转换成 {a:4,b:99}

    a = '?w=3&f=5'
    t = a.split(/=|\&|\?/)
    t.shift()
    k = {}
    k[t[0]] = t[1]
    k[t[2]]= t[3]
    console.log(k)   // {w: "3", f: "5"}
    

    2 dgfhfgh254bhku289fgdhdy675gfh,输出[254,289,675]

    var t = 'dgfhfgh254bhku289fgdhdy675gfh'
    var k = t.match(/[0-9]+/g)
    console.log(k) //  ["254", "289", "675"]
    

    3 var s1 = "get-element-by-id";转换成"getElementById"

    var s1 = "get-element-by-id";  
    s1.replace(/\-\w/g, function(x){return x.substr(1).toUpperCase()})  // "getElementById"
    
    

    4 将 18888888转换为 "$18,888,888.00"

    t = 18888888
    t.toFixed(2).replace(/(?=(\d{3})+\b)/g,',').replace(/^/g, '$$')
    "$18,888,888.00"
    

    5 验证密码问题

    6 括号的作用 以及match的输出以及匹配形式

    teat = '2013-12-12'
    reg = /(\d{4})-(\d{2})-(\d{2})/
    teat.match(reg)
    console.log(RegExp.$1)   //  2013
    console.log(RegExp.$2)   // 12
    console.log(RegExp.$3)   //  12
    

    7 括号的作用,用来替换

    teat = '2013-12-12'
    reg = /(\d{4})-(\d{2})-(\d{2})/
    console.log(teat.replace(reg, '$1/$2/$3'))
    console.log(RegExp.$1)   //  2013
    console.log(RegExp.$2)   // 12
    console.log(RegExp.$3)   //  12
    

    8 replace函数的作用,函数内的参数,这和括号属性是有关系的

    var regex = /(\d{4})-(\d{2})-(\d{2})/; 
    var string = "2017-06-12"; 
    var result = string.replace(regex, function (match, year, month, day) {   
      return month + "/" + day + "/" + year;
     });
     console.log(result)
    
    

    括号出现之后的反向引用,用\1,\2,\3去代表括号内的元素。

    9 待解决的问题 为什么下面的输出会出现空格

    var k = 'snnhuhdheheh'
    console.log(k.split(/n/))
    console.log(k.match(/n/))  \\ ["s", "", "huhdheheh"]
    

    10 将字母的首字母变成大写

    var test = 'you are my girl'
    var reg = /\b\w{1}/g
    test.replace(reg, function(match){
      return match.toUpperCase()
    }) \\ "You Are My Girl"
    

    11 驼峰化

    var test = '-moz-tauia-www '
    var reg = /\-.{1}/g
    console.log(test.replace(reg, function(match){
    return match.substr(1).toUpperCase()
    }))  \\ MozTauiaWww 
    

    反向引用的实际使用方法 匹配<title>sss</title>等双标签的语句。开闭标签要一样。

    其中\1\2\3分别代表第几个引用分组。如果要使分组不会造成编码引用,需要设置成(?:)的格式

    test1 = '<title>hudfuisyu</title>'
    test2 = '<titl>hudfuisyu</title>'
    test3 = '<p>hudfuisyu</p>'
    reg = /\<([^>]+)\>.*\<\/\1\>/g
    console.log(reg.test(test1))  \\ true
    console.log(reg.test(test2))  \\ false
    console.log(reg.test(test3))  \\ true
    

    12 利用反向引用实现:正则去除字符串中出现的连续相同的字符

    str = 'ABBBCCCDDDEEE'   // 匹配到的是出现连续相同的字符组,所以BBB,CCC,DDD都会被匹配到的,再依次替换就可以了
    reg = /(.)\1{1,}/g
    str.replace(reg, '$1')
    "ABCDE"
    
    

    13 关于位置的匹配 (?=p)和 (?!p)

    (?=p)表示的是后面有出现p的位置,当然,在正则匹配中,表示匹配到的字符串后面需要有p
    (?!p) 表示的是后面不能出现p的位置。
    而且位置匹配不会匹配到字符串中,只是一个位置的标志匹配而已,这一点在替换的时候很重要

    举个例子,我想要实现的是,查找字符串,只要出现有两个以上的换行符就匹配结束。而且以@ 为开头。

    regex: /^@\s([\s\S]*?)(?=\n{2,})/gm    // 这里我使用的是(?=\n{2,})这样只要匹配到有两个以上的n的位置。
    当然第一个括号内的?也很重要,是惰性匹配。以防后面也有出现两个\n以上的会继续往后面匹配。
    然后我的目的是匹配之后我要做替换,但是我不希望出现的换行符被我替换掉,所以我要用这个位置属性。
    
    // 其实对这个位置属性的理解,就是,如果单独使用他,那么就是直接匹配到了某个位置,这个位置就是字符与字符之间的空隙
    //  如果和其他的字符结合,那就是结合之后在满足要求的位置处停止。
    // 如果单独使用,就是匹配到那个满足的位置那里。
    

    二 常用方法的总结与实践

    string的方法

    1 search(验证)

    接受一个参数,正则表达式或者RegExp对象。(字符串会转换成正则),返回字符串中第一个匹配项的索引。
    如果没有索引值,就返回-1。始终是从头开始向后查找的。

    注意问题:字符串会转换成正则,所以需要输入的是正则表达式

    var string = "2017.06.27"; 
    console.log( string.search(".") ); // => 0 ,因为‘.‘会被转换成/./就是任意字符。
    //需要修改成下列形式之一 
    console.log( string.search(/\./) ); // => 4
    

    2 replace(替换)

    接受两个参数,第一个是正则对象或者字符串(不会被转成正则表达式)。第二个参数可以是字符串或者函数,如果是字符,还可以使用特殊的字符序列。$&,匹配整个模式的字符串。$n,匹配第n个捕获组的字符串。

    当存在+的时候,对于括号内的匹配,匹配的是最后一项。

    var test = 'eeek'
    var reg = /(\w{1})+/
    test.replace(reg, '$1++')  //"k++"
    

    匹配的是最后一个分组的了。如果想要把每一个分组都列出来,想必是要加多个括号来了。
    replace的一些参数属性

    image.png

    精彩组合!!!:replace 结合 正则表达式()的分组,实现分组替换。

    • 1 把yyyy-mm-dd转换成mm/dd/yyyy,可以用$1$2$3来实现数据的提取与替换
    var reg = /(\d{4})-(\d{2})-(\d{2})/
    var test = '2019-12-12'
    test.replace(reg, '$2/$3/$1')  // 12/12/2019 // 其中,每一个匹配的模块要用()括起来,分别对应$1,$2,$3。如果没有用括号括起来,就不会有这些值啦。
    
    • 2 可以用replace传入函数来实现替换,函数的参数具体如下
    var reg = /(\d{4})-(\d{2})-(\d{2})/
    var test = '2019-12-12'
    test.replace(reg, function(match, w,r,e) {
    return e + '/' + r + '/' + w
    }) // 12/12/2019,其中,match 是匹配的整体字符串,w,r,e分别是子匹配模块。
    
    • 3 或者用下面这种方式,正则对象的特有属性.RegExp.$1,RegExp.$2
    var regex = /(\d{4})-(\d{2})-(\d{2})/; 
    var string = "2017-06-12";
    var result = string.replace(regex, function () {
      return RegExp.$2 + "/" + RegExp.$3 + "/" + RegExp.$1; 
    }); 
     console.log(result);  // 12/06/2017
    

    3 match(匹配)

    接受一个参数,正则表达式或者RegExp对象。
    返回视情况而定。(字符串会改成正则)返回:一个由匹配结果组成的数组。有g,则返回所有匹配结果。// ["2019-12-12"]
    无g,返回的数组第一个元素是匹配的字符串,剩下的是圆括号分组的子表达式。a[n]存放的是$n的内容。 //["2019-12-12", "2019", "12", "12", index: 0, input: "2019-12-12"]

    - 1 提取,通过match的匹配特点,结合()分组匹配,获取子匹配模块。
    var regex = /^(\d{4})\D(\d{2})\D(\d{2})$/; 
    var string = "2017-06-26"; 
    console.log( string.match(regex) );
     // =>["2017-06-26", "2017", "06", "26", index: 0, input: "2017-06-26"]
    

    2 全局匹配和非全局匹配的输出结果区别

    !!!match 在非全局匹配的情况,输出匹配项以及子匹配模块还有index和input。

    match在全局匹配的情况,则只返回匹配的子字符串。不会返回匹配字符串下的子模块。

    var string = "2017.06.27";
    var regex1 = /\b(\d+)\b/; 
    var regex2 = /\b(\d+)\b/g; 
    console.log( string.match(regex1) ); // => ["2017", "2017", index: 0, input: "2017.06.27"],
    console.log( string.match(regex2) );  // => ["2017", "06", "27"]
    
    
    var regex = /^(\d{4})\D(\d{2})\D(\d{2})$/; 
    var regex1 = /^(\d{4})\D(\d{2})\D(\d{2})$/g;
    var string = "2017-06-26"; 
    console.log( string.match(regex) ); //  ["2017-06-26", "2017", "06", "26", index: 0, input: "2017-06-26"]
    console.log( string.match(regex1) ); //  ["2017-06-26"]
    

    4 split(切分)

    接受一个参数,该参数可以分割成多个字符串,参数可以是一个RegExp对象也可以是字符串(字符串不会被看作是正则表达式。)可以有两个参数,第二个参数是返回的数组的长度。

    // 拆分 2017/06/26 2017.06.26 2017-06-26
    var test = '2017/06/26'
    var test2 = '2017.06.26'
    var test3 = '2017-06-26'
    var reg = /[\.\/-]/g
    console.log(test.split(reg)) // [2017,06,26]
    

    正则的一些方法

    1 test()

    接受一个字符串参数。在模式与该参数匹配的情况下则返回true。否则返回false。

    常用语if语句判断中,用于检测某一些信息格式是否正确,只需要部分匹配即可一返回true。如果需要整体去匹配,则需要考虑^$来限定匹配的开始和结束。

    2 exec()

    接受一个参数,要匹配的字符串。返回一个包含匹配信息的数组,包含Input和index两个额外属性。第一个项是与整个模式匹配的字符串,其他项是与模式中的捕获组(也就是括号内的)匹配的字符串。
    有g。每次返回的都只是第一个匹配项,除非再接下来进行操作一次,才会在原来的基础上继续进行匹配。
    无g。每次返回的是第一次匹配项的信息(包含整个匹配的字符串以及字符串内部相应的多个捕获组以及index和input)

    !其实,exec()和字符串的match()是很相似的。
    但是match在全局匹配下却不能给太多完整的信息。
    1 match()在全局匹配的时候,输出的是匹配的项(不包含捕获组)
    2 而exec()在全局捕获的时候,输出的是匹配的项以及相应的捕获组,index,input

    感觉,exec()输出的信息会更多,不过它有一个缺点,就是即使是全局匹配,每次也只是输出第一次匹配的项目信息,要再次输出就得再执行一次exec().所以exec()经常会与循环结合使用

    • // 查看这个例子,需要多次使用exec()才能相应输出匹配项
    
    var test = 'yousiusdh123huus211wwww'
    var reg = /\d{3}(\w{3})/g
    var k = reg.exec(test)
    console.log(k)
    var t = reg.exec(test)
    console.log(t)
    // ["123huu", "huu", index: 9, input: "yousiusdh123huus211wwww"]
    //["211www", "www", index: 16, input: "yousiusdh123huus211wwww"]
    
    • match在全局匹配的情况下,输出的信息却是比exec()少的
    var test = 'yousiusdh123huus211wwww'
    var reg = /\d{3}(\w{3})/g
    var k = reg.exec(test)  // 输出第一次匹配项以及捕获组匹配,index,input
    var l = test.match(reg) // 输出的是所有的匹配项(不包含捕获组)
    console.log(k)  // ["123huu", "huu", index: 9, input: "yousiusdh123huus211wwww"]
    console.log(l) // ["123huu", "211www"]
    
    • match在非全局匹配情况下,输出的信息就和exec()的一样了。
    var test = 'yousiusdh123huus211wwww'
    var reg = /\d{3}(\w{3})/
    var k = reg.exec(test)   // ["123huu", "huu", index: 9, input: "yousiusdh123huus211wwww"]
    var l = test.match(reg) //  ["123huu", "huu", index: 9, input: "yousiusdh123huus211wwww"]
    

    3 正则实例的lastIndex属性

    当使用exec和test方法的时候,正则实例的lastIndex都会跟着改变。如果包含有g,则每次执行完之后都会发生改变,如果不含g,则每次都是从0开始的。

    var test = 'abcabababa'
    var test2 = 'abc'
    var test3 = 'abcab'
    var test4 = 'abdsksj'
    var reg = /ab/g
    console.log(reg.test(test2), reg.lastIndex) // true 2
    console.log(reg.test(test3), reg.lastIndex) //  true 5
    console.log(reg.test(test), reg.lastIndex) //   true 7
    console.log(reg.test(test4), reg.lastIndex)  //  false 0
    

    二 当然,match在非全局匹配模式下,输出的信息就和exec()的一样了。几乎功能和exec()

    四 常见的元字符

    ( { [ \ ^ $| ) ? * + . }]
    

    五 正则表达式中

    字面量形式与构造函数实例的区别

    字面量模式

    var pattern = /[bc]at/g
    

    构造函数形式,j接受的是匹配的字符串模式,另一个是可选的标志字符串

    var pattern2 = new RegExp('[bc]at', g)
    

    2 区别:使用正则表达式字面量始终会共享同一个RegExp实例,而使用构造函数创建的每一个RegExp都是一个新实例。

    注意:首先要知道, 当使用g模式进行test()检测的时候,每多执行一次test(),如果是同一个正则表达式,就会再次从上次检测到的位置开始继续检测,而不是从index=0从头检测。
    所以,通过下面的例子可以发现,第一个for循环,执行第一次的时候是输出true,之后就输出false,因为之后再次执行的就接着上次执行到的位置继续执行,因为正则表达式字面量始终共享同一个RegExp实例
    而第二个例子,则每次都输出true,因为每次都是重新从index= 0 的位置开始检测

    var re = null
                 i;
    for (i =0; i < 10; i++) {
      re = /cat/g
      re.test('catshishsus')
    }
    for (i=0;i<10;i++) {
      re = new RegExp('cat', 'g')
      re.test('catcskjlsl')
    }
    

    五 RegExp构造函数的一些属性

    • RegExp.$1.....RegExp.$9,分别代表一次匹配的九个捕获组
      只要执行了相关的函数,exec(),test()以及match(),replace()等,都会相应地将RegExp.$1给填充了。
    var test = 'yousiusdh123rhuus211wwww'
    var reg = /\d{3}(\w{3})/
     test.match(reg)
    console.log(RegExp.$1) //  rhu
    
    • 当然,还有更多的属性。
    image.png

    参考链接:
    http://imweb.io/topic/56e804ef1a5f05dc50643106
    https://juejin.im/post/5965943ff265da6c30653879

    相关文章

      网友评论

          本文标题:Javascript中的正则表达式总结与实践

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