• 正则表达式,你不会用太可惜



    在这里插入图片描述

    说明

    后面的介绍中,我会说某些规则占位或者不占位,占位就是指匹配的结果中,有字符和这符号所表示的规则有直接联系,不占位就是所匹配的结果中没有字符和这符合有直接联系。

    ^在开头属于不占位符,开始符

    var reg1 = /^ab/
    const result = 'abABCDab'.match(reg)
    console.log(result) //  ['ab'] 匹配的结果ab和^没有直接联系,规则/^ab/中,a和b是两位,所以匹配的一个字符串也只有两位
    
    • 1
    • 2
    • 3

    创建正则表达式的三种方式

    方式一

    var reg1 = /ab/
    
    • 1

    方式二

    var reg2 = new RegExp(reg1)
    
    • 1

    方式三

    var reg3 = RegExp(reg1)
    
    • 1

    有什么区别呢

    var reg1 = /ab/
    var reg2 = new RegExp(reg1)
    var reg3 = RegExp(reg1)
    console.log(reg1 === reg3) // true
    console.log(reg1 === reg2) // false
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如上代码所述,reg1和reg3本质上是同一个正则对象,相当于将reg1赋值给了reg3,但reg2不同,它深度拷贝了reg1。

    再验证一下

    var reg1 = /ab/
    var reg2 = new RegExp(reg1)
    var reg3 = RegExp(reg1)
    reg1.name = 'dx'
    console.log(reg2.name) // undefined
    console.log(reg3.name) // dx
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    正则表达式修饰符

    修饰符一共就只有三个 g/i/m,它们通常出现在正则表达式的最后面,可以自由组合,顺序无所谓,但每个修饰符只能出现一次。
    /ab/g /ab/ig /ab/gm /ab/igm /ab/gim

    修饰符描述
    i执行对大小写不敏感的匹配。
    g执行全局匹配(查找所有匹配而非在找到第一个匹配后停止)
    m执行多行匹配

    i (IgnoreCase)

    忽略字母大小写

      const reg = new RegExp(/ab/i)
      const result = 'djwiAB'.match(reg)
      console.log(result)
      const result2 = 'fsadfaB'.match(reg)
      const boolean1 = reg.test('fsadfaB')
      console.log(result2)
      console.log(boolean1)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    result的结果 ['AB', index: 4, input: 'djwiAB', groups: undefined] 这是一个类数组,第0位匹配到AB
    result2的结果 ['aB', index: 5, input: 'fsadfaB', groups: undefined] 类数组第0位匹配aB
    boolean1的结果是true
    以上三个结果都表明,i作为忽略大小写的修饰符,挺好使,而且也经常用。

    g (global)

    全局匹配修饰符

      const reg = new RegExp(/ab/g)
      const result = 'abABCDab'.match(reg)
      console.log(result) //  ['ab', 'ab']
      const result2 = 'abaabb'.match(/ab/)
      console.log(result2) //  ['ab', index: 0, input: 'abaabb', groups: undefined]
    
    • 1
    • 2
    • 3
    • 4
    • 5

    result 匹配到了两次,而result2只匹配到了一次。g的作用就是找到整个字符串中所有符合条件的字符。如果没有g就只会匹配到第一个。

      const reg = new RegExp(/ab/ig)
      const result = 'abABCDab'.match(reg)
      console.log(result) // ['ab', 'AB', 'ab']
    
    • 1
    • 2
    • 3

    g结合i再匹配了一下,忽略了大小写,AB也被匹配进去了。

    m (multiple lines)

    支持多行匹配,看个例子,简单说明一下m的用法,很少用到。
    \n表示换行,^ab表示匹配字符串中以ab开头的那一部分。

      const reg = new RegExp(/^ab/) 
      const result = 'ABCD\nab'.match(reg)
      console.log(result) // null
    
    • 1
    • 2
    • 3

    如果加一个m,可以看到结果result中 有一个index为5的属性,证明\n后的ab被匹配到了

      const reg = new RegExp(/^ab/m) 
      const result = 'ABCD\nab'.match(reg)
      console.log(result) // ['ab', index: 5, input: 'ABCD\nab', groups: undefined]
    
    • 1
    • 2
    • 3

    m的作用就是每遇到一次\n就认为后面的内容是全新的一行,当然也就符合以ab开头的匹配规则。

      const reg = new RegExp(/^ab/gim) 
      const result = 'ABCD\nab'.match(reg)
      console.log(result) // ['AB', 'ab']
    
    • 1
    • 2
    • 3

    正则表达式

    [ ]

    每一个[ ]表示一位,而里面的内容,就是这一位的取值范围
    [abc] 从abc中取一个出来,a或者b或者c都符合这个位置的要求
    [0a] 0或者a都符合这个位置的要求

      const reg = new RegExp(/[ab]/g) 
      const result = 'ABCDab'.match(reg)
      console.log(result) // ['a', 'b']
    
    • 1
    • 2
    • 3

    result匹配到了两个,是因为g修饰符,一个a和一个b,是因为匹配规则是匹配一位,一个[]表示一位,这一位可以是a,也可以是b

    []里面可以加^,和之前的^不同,方括号里的^表示凡是不在方括号表示范围的字符都可以。

      const reg = new RegExp(/[^ab]/g) // 查找字符串中不是a或者不是b的一位字符 
      const result = 'ABCDab'.match(reg)
      console.log(result) //['A', 'B', 'C', 'D']
    
    • 1
    • 2
    • 3

    []里面可以加-,表示一定的范围,如果你想让某一位是数字,难道要[0123456789],可以使用[0-9]
    -在其它地方使用都没有特殊意义,只是占一位的字符-
    [0-9] 表示这一位是数字0到9都可以
    [a-z] 表示这一位是字母a到z都可以
    [A-Z]表示这一位是字母A到Z都可以
    [A-z]表示这一位是字母A到z都可以,这就囊括了所有的字母,但A必须在前面,因为大写字母的ascll码更小,不能[z-A],会报错。

      const reg = new RegExp(/[^0-9]/g)  // 匹配出所有非数字,
      const result = '123AB'.match(reg)
      console.log(result) // ['A', 'B']
    
    • 1
    • 2
    • 3
      const reg = new RegExp(/[^0-9A-z]/g)  // 匹配出所有非数字非字母
      const result = '123AB*-'.match(reg)
      console.log(result) // ['*', '-']
    
    • 1
    • 2
    • 3

    ()

    ()可以加 || 表示或

      const reg = new RegExp(/(a|b)/g) 
      const result = 'ABCDab'.match(reg)
      console.log(result) // ['a', 'b']
    
    • 1
    • 2
    • 3

    (a|b)表示|左边的a或者右边的b都符合匹配要求,好像和[ab]没啥区别,

      const reg = new RegExp(/(abc|bcd)/ig) 
      const result = 'ABCDabcd'.match(reg)
      console.log(result) //['ABC', 'abc']
    
    • 1
    • 2
    • 3

    (abc|bcd) 表示连着的abc或者连着的bcd都可以

    ()里面的是左右二选一组,一组可能有多位,而[]里面是范围内选一位。

    元字符

    .

    在正则表达式中某些字母或字母组合具有特殊意义,只列出重要的

    元字符特殊意义
    .查找单个字符,除了换行符\n或行终止符\r
      const reg = new RegExp(/./g) 
      const result = 'AB1\n-\r0'.match(reg)
      console.log(result) // ['A', 'B', '1', '-', '0']
    
    • 1
    • 2
    • 3

    w 是word的缩写

    元字符特殊意义
    \w查找数字或字母,默认一位。和[A-z0-9] 表示意义相同
    \W\w相反,查找非数字非字母的字符,默认一位 和[^A-z0-9] 表示意义相同
      const reg = new RegExp(/\w\w/g) // 匹配所有连续两位是字母或数字的片段 
      const result = 'AB1\n-\r ba11'.match(reg)
      console.log(result) // ['AB', 'ba', 11]
    
    • 1
    • 2
    • 3
      const reg = new RegExp(/\W\W/g) // 匹配所有连续两位是非字母并且非数字的片段 
      const result = 'AB1\n-\r ba11'.match(reg)
      console.log(result) // ['\n-', '\r ']
    
    • 1
    • 2
    • 3

    d 是digit的缩写

    元字符特殊意义
    \d查找任意数字,默认一位。和[0-9] 表示意义相同
    \D\d相反,查找非数字 和[^0-9] 表示意义相同
      const reg = new RegExp(/\d\d/g) // 匹配所有连续两位是数字的片段 
      const result = 'AB177b12a'.match(reg)
      console.log(result) // ['17', '12']
    
    • 1
    • 2
    • 3
      const reg = new RegExp(/\d\D/g) // 匹配所有连续两位,一位数字连接一位非数字,并且数字在前的片段 
      const result = 'AB177b12a'.match(reg)
      console.log(result) // ['7b', '2a']
    
    • 1
    • 2
    • 3

    s 是 space的缩写

    元字符特殊意义
    \s查找空格或\n\r\t\v\f,默认一位。
    \S\s相反,默认一位
     const reg = new RegExp(/\s/g) 
     const result = 'AB1\n-\r\t\v\f 0  '.match(reg)
     console.log(result) // ['\n', '\r', '\t', '\v', '\f', ' ', ' ', ' ']
    
    • 1
    • 2
    • 3
     const reg = new RegExp(/\S\s/g) 
     const result = 'AB1\n-\r\t\v\f 0  '.match(reg)
     console.log(result) // ['1\n', '-\r', '0 ']
    
    • 1
    • 2
    • 3

    其它间隙元字符

    元字符特殊意义
    \n查找换行符 占位
    \f查找换页符 占位
    \r查找回车符 占位
    \t查找制表符 占位
    \v查找垂直制表符 占位

    不占位修饰符

    一般都是都附近的规则有位置上的修饰,比如要求n必须在开头,或必须在结尾,或必须诶着什么,或者不能诶着什么

    b是border的缩写

    不占位修饰符特殊意义
    \b边界字符,一段连续字符 开始的那一位 或者 一段连续字符 结束的那一位 不占位
    \B非边界字符,不占位

    看例子更容易理解

     const reg = new RegExp(/\b\w/g) // 查找与间隙相连,并且间隙在前的字母或数字 一位,因为\b不占位
     const result = 'dengxi is 123'.match(reg)
     console.log(result) // [d, i, 1]
    
    • 1
    • 2
    • 3
     const reg = new RegExp(/\w\b/g) // 查找与间隙相连,并且字母或数字在前 一位,因为\b不占位
     const result = 'dengxi is 123'.match(reg)
     console.log(result) // [i, s, 3]
    
    • 1
    • 2
    • 3

    字符串开头,空格,\n,\r,\t,\f,\v 字符串结尾,这些都算间隙

     const reg = new RegExp(/\w\b/g) // 查找与间隙相连,并且字母或数字在前的 一位 字符,因为\b不占位
     const result = 'dengxi\nyang\rxi'.match(reg)
     console.log(result) // ['i', 'g', 'i']
    
    • 1
    • 2
    • 3
     const reg = new RegExp(/\w\B/g) // 所有后面不跟着间隙的数字或者字母 一位,因为\B不占位
     const result = 'dengxi\nyang\rxi'.match(reg)
     console.log(result) // ['d', 'e', 'n', 'g', 'x','y','a','n','x']
    
    • 1
    • 2
    • 3

    ^

    在开头放置表示行开头,在[]中放置表示中括号的范围取反。

    不占位修饰符特殊意义
    ^n找到字符串中以n作为开头的那一部分,n可以是一位或者多位,^本身不占位
    [^n] 找到非n提供范围内的一位字符, ^本身不占位

    \n是换行,\r回车,都会出现新的一行

    另外修饰符m是能够换行匹配的关键

     const reg = new RegExp(/^\w\w/gm) 
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
     console.log(result) // ['12', '11', 'bb', '02']
    
    • 1
    • 2
    • 3
     const reg = new RegExp(/^\w\w/g) 
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
     console.log(result) // ['12']
    
    • 1
    • 2
    • 3

    $

    在末尾放置放置,表示在行末尾

    不占位修饰符特殊意义
    n$找到字符串中以n作为结尾的那一部分,n可以是一位或者多位,$本身不占位

    \n是换行,\r回车,都会出现新的一行
    另外修饰符m是能够换行匹配的关键

     const reg = new RegExp(/\w\w$/gm) 
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
     console.log(result) // ['B1', '11', '01', '02']
    
    • 1
    • 2
    • 3
     const reg = new RegExp(/\w\w$/g) 
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
     console.log(result) // ['02']
    
    • 1
    • 2
    • 3

    ?=?!

    不占位修饰符特殊意义
    (?=n)匹配任何其后紧接指定字符串 n 的字符串。
    (?!n)匹配任何其后没有紧接指定字符串 n 的字符串。

    ?=n要配合小括号使用,否则不生效

     const reg = new RegExp(/\w(?=1)/g) // 匹配后面跟着1的数字或字母,(?=1)不占位,所以匹配出来的结果只有1位
     const result = '12AB21\n21\rbb\tcc\vdd\f01\n02'.match(reg)
     console.log(result) //['2', '2', '0']
    
    • 1
    • 2
    • 3
     const reg = new RegExp(/\w\w(?!\w)/g) // 匹配后面没有数字或字母跟着的 连续两位数字或字母,(?!\w)不占位,所以匹配出来的结果只有2位
     const result = '12AB21\n21\rbb\tcc\vdd\f01\n02'.match(reg)
     console.log(result) // ['21', '21', 'bb', 'cc', 'dd', '01', '02']
    
    • 1
    • 2
    • 3

    量词

    量词本身是不占位的,但是,量词会将临近它的 有符占位数的规则 做一个乘法,比如 /\w{2}/的意义就相当于/\w\w/,就是将\w给乘以2。

    量词特殊意义
    n{X}匹配包含 X 个 n 的序列的字符串。
    n{X,Y}匹配包含 X 至 Y 个 n 的序列的字符串。
    n{X,}匹配包含至少 X 个 n 的序列的字符串。

    X和Y都是数字,前面的小,后面的大,n表示任意拥有占位数的正则规则。

     const reg = new RegExp(/\w{2}/g) // 匹配两位,连续的是字母或数字的字符串
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
     console.log(result) // ['12', 'AB', '11', 'bb', 'cc', 'dd', '01', '02']
    
    • 1
    • 2
    • 3

    正则表达式的贪婪原则,能匹配长的,就不匹配短的,下面的规则中,是两位或者三位都可以,但优先查看是否三位满足正则的要求。

     const reg = new RegExp(/\w{2,3}/g) // 匹配两位或者三位,优先匹配三位,连续每个字符都是数字或者字母的字符串
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n02'.match(reg)
     console.log(result) // ['12A', 'B1', '11', 'bb', 'cc', 'dd', '01', '02']
    
    • 1
    • 2
    • 3

    至少两位,尽可能多位

     const reg = new RegExp(/\w{2,}/g) // 匹配 至少连续两位的字符串,尽可能长,要求每一位都是字母或数字
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n0244'.match(reg)
     console.log(result) // ['12AB1', '11', 'bb', 'cc', 'dd', '01', '0244']
    
    • 1
    • 2
    • 3

    下限设置为0

     const reg = new RegExp(/\w{0,4}/g) // 匹配整个字符串,最多4位,至少0位,表示可以为空,0乘以任何东西都是0,所以匹配出了空。
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n0244'.match(reg)
     console.log(result) // ['12AB', '1', '', '11', '', 'bb', '', 'cc', '', 'dd', '', '01', '', '0244', '']
    
    • 1
    • 2
    • 3

    有的人可能会尝试着设置一个上限,而不设置下限,下限连0都不是,其实没什么意义,也没有这个规则

     const reg = new RegExp(/\w{, 4}/g) 
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n0244'.match(reg)
     console.log(result) // null
    
    • 1
    • 2
    • 3
    量词特殊意义
    n+匹配任何包含至少一个 n 的字符串。相当于 n{1,}
    n*匹配任何包含零个或多个 n 的字符串。相当于 n{0,}
    n?匹配任何包含零个或一个 n 的字符串。相当于n{0, 1}

    一样有贪婪原则

     const reg = new RegExp(/\w*/g) // 匹配整个字符串,至少0位,表示可以为空,0乘以任何东西都是0,所以匹配出了空。
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n0244'.match(reg)
     console.log(result) ['12AB1', '', '11', '', 'bb', '', 'cc', '', 'dd', '', '01', '', '0244', '']
    
    • 1
    • 2
    • 3
     const reg = new RegExp(/12?/g) // 匹配整个字符串,至少1位1,2可能乘以0不存在,2可能乘以1为一位,
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n12222222'.match(reg)
     console.log(result) // ['12', '1', '1', '1', '1', '12']
    
    • 1
    • 2
    • 3
     const reg = new RegExp(/12+/g) // 匹配整个字符串,至少1位1,1位2,2可能乘以1,2可能乘以很多位,贪婪原则
     const result = '12AB1\n11\rbb\tcc\vdd\f01\n12222222'.match(reg)
     console.log(result) // ['12', '12222222']
    
    • 1
    • 2
    • 3

    正则的反向引用 (n)\数字

    这个非常有用,很多人都不知道正则还有这种用法,可能学到上面就已经结束了,在 w3c school中,也从来没有提过这种用法。

    想要获取字符串中,所有形如aabb的字符串,1122可以,ccdd也可以,只要第一位和第二位相同,第三位和第四位相同即可。

    /\w{2}\w{2}/?这肯定不能解决,每一次\w都是独立随机的,这相当于\w\w\w\w确实是四位,但不能保证第一位和第二位相同啊。

    所以为了解决形如aabb的问题,就必须得获取第一位的实际内容,然后给第二位,获取第三位的实际内容,给第四位。

    /(\w)\1(\w)\2/ 用法(n)\数字,如果是第一次使用,那数字就是1,如果是第二次使用,数字就是2,并且\1本身也是占位的,所以/(\w)\1(\w)\2/这就是四位。

    \数字会重复(n)n的实际内容,不是正则规则上的重复,而是匹配出字符串内容的重复。

     const reg = new RegExp(/(\w)\1(\w)\2/g) 
     const result = 'adad ccdd cccc bbpp fhajw'.match(reg)
     console.log(result) // ['ccdd', 'cccc', 'bbpp']
    
    • 1
    • 2
    • 3

    RegExp 对象方法

    常用的方法就俩,exec() and test()

    exec() 是 execute的缩写

    execute就是执行,所以exec只会执行依次匹配,正则表达式后面的g没啥用

     const reg = new RegExp(/(\w)\1(\w)\2/g) 
     const result = reg.exec('adad ccdd cccc bbpp fhajw')
     console.log(result) // ['ccdd', 'c', 'd', index: 5, input: 'adad ccdd cccc bbpp fhajw', groups: undefined]
    
    • 1
    • 2
    • 3

    但是exec会返回一些特殊的东西,其中数组的第一位和第二位很重要,它们对应的就是正则反向引用 匹配到的真实字符。

    test()

    test()传入需要匹配的字符串,如果字符串符合正则表达式的规则,就返回true,如果字符串不符合,就返回false

     const reg = new RegExp(/(\w)\1(\w)\2/g) 
     const result = reg.test('adad ccdd cccc bbpp fhajw')
     const rsult1 = reg.test('dengxi yangxi')
     console.log(result,rsult1) // true false
    
    • 1
    • 2
    • 3
    • 4

    支持正则表达式的 String 对象的方法

    方法名介绍
    search检索与正则表达式相匹配的值。
    match找到一个或多个正则表达式的匹配。
    replace替换与正则表达式匹配的子串。
    split把字符串分割为字符串数组。

    search()

    最没用的就是search,返回的是第一个符合正则规则所在字符的位置
    正则里面的g没用,只匹配第一个,也只返回第一个,ccdd是能匹配到的第一个,c所在的下标是5,所以结果返回5,如果整个字符串都没找到返回-1

     const reg = new RegExp(/(\w)\1(\w)\2/g) 
     const result = 'adad ccdd cccc bbpp fhajw'.search(reg)
     const result1 = 'dengxi yangxi'.search(reg)
     console.log(result,result1) // 5 -1
    
    • 1
    • 2
    • 3
    • 4

    match()

    用过很多次了,很实用。

    split()

    将符合正则规则的字符串片段作为分界限,拆分字符串位数组。通常使用split都是传入固定的字符串,作为分界,但有了正则后,只要这些分界有某种规律,它们不必相同,也能直接拆成数组。

     const reg = new RegExp(/\W/g) 
     const result = '12FSAF#FJA*FJD*JDKA/DASF/FASEF'.split(reg)
     const result1 = 'my name is dengxi'.split(reg)
     console.log(result) //['12FSAF', 'FJA', 'FJD', 'JDKA', 'DASF', 'FASEF'] 
     console.log(result1)  //['my', 'name', 'is', 'dengxi']
    
    • 1
    • 2
    • 3
    • 4
    • 5

    replace()

    真正的王者,最实用的方法,一个字就是香。

    我想获取当前的时间,并且以 year-month-day hh:mm:ss的格式返回。

    function getTime() {
    	const NowDate = new Date()
    	const time = NowDate.toString() // 'Thu Nov 16 2023 17:08:25 GMT+0800 (中国标准时间)'
    	const month = NowDate.getMonth() // 这里偷懒了,用这种方法获取了月份
    	const reg = /.* (\d{2}) (\d{4}) ((\d|:){8}) .*/ // 这个正则能匹配到整个字符串,但将其中关键信息抽取了出来
    	const result = time.replace(reg, function($,$1,$2,$3){
    		console.log($) // Thu Nov 16 2023 17:27:51 GMT+0800 (中国标准时间)
    		console.log($1) // 16
    		console.log($2) // 2023
    		console.log($3) // 17:15:32
    		
    		return `${$2}-${month + 1}-${$1} ${$3}`
    	})
    	
    	return result  // '2023-11-16 17:27:51'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    deng-xi-and-yang-xi 转变为小驼峰命名 dengXiAndYangXi

    将诶着-的字符找出来,替换成对应的大写就可以了,一看就跟

    function changeStringName(str) {
    	const reg = new RegExp (/-(\w)/g)
    	const result = str.replace(reg,function($,$1) {
    		console.log($)
    		console.log($1)
    		return $1.toUpperCase()
    	})
    
    	return result
    }
    
    var a = changeStringName('deng-xi-and-yang-xi')
    console.log(a) // dengXiAndYangXi
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

  • 相关阅读:
    基于PHP+MySQL毕业生档案管理系统
    Android~快捷方式兼容适配
    H5的基础
    【Linux】Centos 8 服务器部署:阿里云域名注册、域名解析、个人网站 ICP 备案详细教程
    c语言免杀火绒
    url后面直接拼接参数
    自定义SonarQube Java规则
    Docker Compose:简化多容器管理的利器
    任意文件下载
    黑盒测试用例设计方法案例与练习题
  • 原文地址:https://blog.csdn.net/glorydx/article/details/134430088