《前端竹节》(2)【正则表达式】

正则表达式在前端开发中,对于字符串处理任务来说,绝对是一件可以祭出的大杀器。同时对于前端开发人员来说也是一项基本技能,但若只是停留在能看懂,知道去哪查的阶段,那距离得心应手地运用差的可能不止一步两步。

行业总习惯通过工作年限,来粗略估计一个工程师的能力与水平,因为随着时间的延展总觉得会积累下些许经验。但年限这种间接的衡量指标太因人而异,太难得到及时的正反馈。后来慢慢地发现,只有基于自己独立地思考,总结并输出才会感到真实的成长,就像竹子长一段就得生一个节。

一. 正则使用分类

正则表达式(后文简称为“正则”)可划分出两种使用方式:

通过正则字面量与通过RegExp构造函数创建出来的正则对象,在不考虑访问正则对象属性的情况下,是等价的。如果需访问正则对象的属性,需通过RegExp初始化正则实例。
  1. 正则表达式字面量 /正则匹配模式/[修饰符]
    字符串对象内置了一些与使用正则表达式相关的方法,这些方法的入参就是所需的正则表达式字面量

    • match返回一个数组或者在未匹配到时返回null
    • search返回匹配到的位置索引,或者在失败时返回-1
    • replace使用替换字符串替换掉匹配到的子字符串
    • split一个使用正则表达式或者一个固定字符串分隔一个字符串,并将分隔后的子字符串存储到数组中
  2. RegExp构造的正则表达式对象 new RegExp("正则匹配模式"[, 修饰符])
    通过正则构造函数实例化的正则对象,同样也具有类似的方法

    • exec返回一个数组或者在未匹配到时返回null
    • test匹配到返回true否则false

二. 正则的使用(持续更新)

  1. 当匹配到时,execmatch返回结果的不同

    • 字符串的match方法,当正则表达式按照字面量传参时,返回匹配到字符串的数组

      // 字符串的match方法
      var str = "cdbbdbsbz"
      var ret1 = str.match(/d(b+)d/g)
      console.log(ret1) // ["dbbd"]

      当传参为正则对象时,返回值与exec方法相同。

    • 正则对象的exec方法,返回从索引值处开始首次匹配到结果的字符串数组,数组的第一个元素为结果字符串,若匹配模式中存在括号,则括号中的子模式在本次匹配中得到的字符串,依次排列在结果数组中。与此同时,该数组对象还附带了一些相关的属性。

      // 正则对象的exec方法
      var regExp = new RegExp(/d(b+)d/, 'g')
      var ret2 = regExp.exec(str)
      console.log(ret2) // ["dbbd", "bb", index: 1, input: "cdbbdbsbz", groups: undefined]
      对象 属性 描述 例子中对应的值
      retArray 匹配到的字符串,和所有被记住的字符串 ["dbbd", "bb"]
      index 本次匹配结果,开始的索引值 1
      input 初始字符串 "cdbbdbsbz"
      [0] 本次匹配到的字符串 "dbbd"
      regExp lastIndex 下一个匹配的索引值 5
      source 匹配模式的文本 "d(b+)d"
  2. 使用括号的子字符串匹配(组匹配)
    拿上例的匹配模式来看/d(b+)d/g,括号中匹配到的子字符串,会被记录在数组元素[1],...,[n]中,且保存数量可以是无限的。除了通过js直接使用外,还可以这样使用:

    var name = "John Tom"
    var newName = name.replace(/(\w+)\s(\w+)/, "$2 $1")
    console.log(newName) // Tom John
  3. 正则表达式修饰符

    • g:全局搜索
    • i:不区分大小写搜索
    • m:多行搜索,^$匹配的开始或结束输入字符串中的每一行,而非整个输入字符串
    • u:开启Unicode模式,用来正确处理大于\uFFFF的字符
    • y:粘连匹配,类似全局搜索,但不同是其要求在lastIndex的位置发现匹配,而g是从lastIndex处开始搜索,也就是说粘连匹配y模式中隐藏了头部匹配的标志^
  4. 具名组匹配
    上面有讨论过组匹配的概念和用法,通过数组下标的方式使用总会带来些许不便,所以在ES2018中引入了具名组匹配,允许为每一个组匹配指定一个名字,以方便阅读和调用,来看例子:

    // 之前的组匹配
    const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;
    const matchObj = RE_DATE.exec('1999-12-31');
    const year = matchObj[1]; // 1999
    const month = matchObj[2]; // 12
    const day = matchObj[3]; // 31
    // 使用具名组匹配
    const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
    const matchObj = RE_DATE.exec('1999-12-31');
    const year = matchObj.groups.year; // 1999
    const month = matchObj.groups.month; // 12
    const day = matchObj.groups.day; // 31

三. 正则匹配模式

下表列出了在正则表达式中,可以利用的特殊字符的完整列表和描述

字符含义
/1. 在非特殊字符前,表示特殊用途; 2. 在特殊字符前,转义为字面量;3. 在new RegExp("pattern") 中需将 进行转义。
^匹配输入的开始。若设置多行匹配,则也匹配换行符后紧跟的位置
$匹配输入的结束。若设置多行匹配,则也匹配换行符前的位置。
*匹配前一个表达式0次或多次。等价于 {0,}
+匹配前面一个表达式1次或者多次。等价于 {1,}
?1. 匹配前面一个表达式0次或者1次。等价于 {0,1};2. 如果紧跟在任何量词 *、 +、? 或 {} 的后面,将会使量词变为非贪婪的(匹配尽量少的字符),和缺省使用的贪婪模式(匹配尽可能多的字符)正好相反。
.匹配除换行符之外的任何单个字符
(x)匹配 x 并且记住匹配项
(?:x)匹配 x 但是不记住匹配项(非捕获括号)
x(?=y)匹配 x 仅仅当x后面跟着y (正向肯定查找)
x(?!y)匹配 x 仅仅当x后面不跟着y(正向否定查找)
{n}匹配了前面一个字符刚好发生了n次(n为正整数)
{n,m}匹配前面的字符至少n次,最多m次
[xyz]表示字符集合,匹配方括号的中任意字符
[^xyz]表示一个反向字符集,匹配没在方括号的中任意字符
[\b]匹配一个退格(U+0008)
\b匹配一个词的边界
\b匹配一个非单词边界
\cX当X是处于A到Z之间的字符的时候,匹配字符串中的一个控制符
\d匹配一个数字,等价于[0-9]
\d匹配一个非数字字符,等价于[^0-9]
\f匹配一个换页符
\n匹配一个换行符
\r匹配一个回车符
\s匹配一个空白字符,包括空格、制表符、换页符和换行符
\s匹配一个非空白字符
\t匹配一个水平制表符
\v匹配一个垂直制表符
\w匹配一个单字字符(字母、数字或者下划线)
\w匹配一个非单字字符
\n它返回最后的第n个子捕获匹配的子字符串(捕获的数目以左括号计数)
\0匹配 NULL (U+0000) 字符,不要在这后面跟其它小数,因为 0<digits> 是一个八进制转义序列。

相关推荐