分组

通过括号将相关的元素归拢到一起作为一个整体。
身份证是一个长度为15或者18个字符的字符串,如果是15位,则全部由数字组成,首位不能为0;如果是18位,前17位全部是数字,首位同样不能为0,末位可能是数字,也可能是字母x

15位身份证号码 [1-9]\d{14}
18位身份证号码 [1-9]\d{14}\d{2}[0-9xX]

也就是后面的\d{2}[0-9xX]可以出现1次,也可以不出现。因此可以将其作为一个整体,配合量词?,因此匹配身份证号码的正则表达式可以写成[1-9]\d{14}(\d{2}[0-9xX])?

多选结构

多选结构的形式是(option1|option2|…),在括号内以竖线|分割开多个子表达式,这些子表达式也叫多选分支,在一个多选结构内,多选分支的数目没有限制。在匹配时,整个多选结构被视为单个元素,只要其中某个分支能够匹配,整个多选结构就能匹配成功;如果所有分支都不能匹配,则整个多选结构匹配失败。
可以用多选结构匹配身份证号码([1-9]\d{14}|[1-9]\d{16}[0-9xX])

引用分组

编号

括号不仅能把有联系的元素归拢起来进行分组,而且会保存每个分组真正匹配的文本,等到匹配结束后,可以(通过$num)引用这些分组真正匹配的文本。因为捕获了文本,所以这种功能叫作捕获分组,对应的括号叫作捕获型括号。编号规则是根据开括号出现的顺序从左向右来计数,从1开始

  1. '2020-10-03'.replace(/(\d{4})-(\d{2})-(\d{2})/, '$3/$2/$1') // 03/10/2020

新手容易弄错分组的结构

  1. '2020-10-03'.replace(/(\d{4})-(\d{2})-(\d{2})/,'$1') // 2020
  2. '2020-10-03'.replace(/(\d){4}-(\d{2})-(\d{2})/,'$1') // 0
  3. // 在第一个表达式中,编号为1的分组对应的括号是(\d{4}),即匹配4个数字。在第二个表达式中,编号为1的分组对应的括号是(\d),即匹配1个数字,因为后面有量词{4},所以整个括号作为单个元素,要重复出现4次,而且编号都是1。于是每重复出现一次,就要更新一次匹配结果。所以在匹配过程中,编号为1的分组匹配的文本值,依次是2、0、2、0,最后结果是0。

反向引用

反向引用即允许正则表达式内部(通过\num)引用之前的捕获分组匹配的文本。
英文单词中会有重叠出现的字母,比如shoot,bee,如何检查某个单词是否包含重叠出现的字母呢?

  1. let reg = /([a-zA-Z])\1/
  2. reg.test('shoot') // true
  3. reg.test('bee') // true
  4. reg.test('element') // false
  5. reg.test('next') // false

命名分组

二义性歧义问题
无论是$10还是\10那么到底表示的是第10个捕获分组,还是第一个捕获分组\1,后面跟一个字符0呢?
JavaScript中,如果确实存在10个分组那么表示的是第10个捕获分组,如果不存在10个分组,那么表示的就是第一个捕获分组\1,后面跟一个字符0。

  1. '0123456789'.replace(/^(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)$/,'$10') // 9
  2. '0123456789'.replace(/^(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)(\d)$/,'$11') // 01

捕获分组通常用数字编号来标示,但是会存在正如上面谈的二义性歧义问题,而且也不够直观,因此正则提供了命名分组的功能,即给各个分组起一个容易辨别的名字。es2017提供了对命名分组的支持。

  • 定义命名分组:(?regexp)
  • 引用分组:$
  • 反向引用:\k ```javascript ‘2020-10-03’.replace(/(?\d{4})-(?\d{2})-(?\d{2})/, ‘$/$/$‘ // 2020/10/03

/(?[a-zA-Z])\k/.test(‘aa’) // true /(?[a-zA-Z])\k/.test(‘ab’) // false

  1. <a name="yB7H4"></a>
  2. ## 非捕获分组
  3. 无论是否需要引用分组,只要出现了括号,正则表达式在匹配时就会把括号内的子表达式存储起来以提供引用。如果不需要这些引用,保存这些信息无疑会影响性能,为解决这个问题,正则提供了非捕获分组,只要在开括号后紧跟一个问号和冒号(?:regexp),这样的括号叫作非捕获型括号,此时编号同样会按开括号出现的顺序从左到右从1计数,只是必须以捕获分组为准,会略过非捕获分组。
  4. ```javascript
  5. '2020-10-04'.replace(/(?:\d{4})-(\d{2})-(\d{2})/,'$1') // 10