正则表达式之零宽断言

1,594 阅读2分钟

场景

有时我们需要匹配一些字符,但要求前后必须是特定内容,但又不想把这些特定内容匹配到最终结果中,这时,使用正则的零宽断言能实现我们想要的效果

概念:什么是零宽断言

  • 零宽:意如其名,是一种零宽度的匹配,即它匹配到的内容不会保存到匹配结果中去,
  • 断言: 做出的假设,在正则中可以理解为是正则表达式的一种条件判断(当这个条件满足时才正则才能匹配成功),后面我会用例子去验证这个说法

分类

  • 按编写位置分:
    • 先行断言(写在结果的后面):如果条件成立则匹配前面的结果
    • 后发断言(使用<符号,写在结果的前面):如果条件成立则匹配后面的结果
  • 按条件分(零宽断言是否能匹配)
    • 正向:匹配(使用=
    • 负向:不匹配(使用!

根据位置和条件组合出以下零宽断言格式

  1. a(?=b) :目的要匹配a,但要求a后面一定要包含字符b才能匹配(如果a后面有b,则匹配a)
  2. a(?!b) :目的要匹配a,但要求a后面一定不能包含字符b才能匹配(同上)
  3. (?<=b)a :目的要匹配a,但要求a前面一定要包含字符b才能匹配(同上)
  4. (?<!b)a :目的要匹配a,但要求a前面一定不能包含字符b才能匹配(同上)

应用

  • 把双花括号中的字符替换成相应数据
    const template = `姓名:{{username}},年龄:{{age}}`
    const user = {username:'laoxie',age:18}
    
    // 如果[a-z]+前面匹配`{{` 以及后面匹配 `}}`才会去匹配[a-z]+的结果,但`{{` 和 `}}`都不会进入最终匹配结果
    const reg = /(?<=\{\{)[a-z]+(?=\}\})/g
    const result = template.replace(reg,(key)=>{
        return user[key]
    })
    console.log(result); // => 姓名:{{laoxie}},年龄:{{18}}
  • 给金额添加逗号以方便阅读(如:1000000 -> 1,000,000)
    const amount = '1000000'
    amount.replace(/\B(?=(\d{3})+(?!\d))/g,',') // => 1,000,000

    // >说明:`\B` 匹配一个非单词边界(即两个数字之间的位置)
    // 如果不用零宽断言,则为以下结果 
    amount.replace(/\B/g,','); // => 1,0,0,0,0,0,0
    
    // 所以使用断言后表示:如果\B后还有3位数字且3位数字后不能再有数字时,才到\B替换成逗号`,`

所以,合理使用零宽断言,能让我们的正则匹配更加强大,是时候表演真正的技术了

PS:js中的后发断言在ES9中才得以支持,注意浏览器支持情况