正则训练营 | 4.正则中的逻辑语句:分支 + 分组 + 模式

1,281 阅读3分钟

本文正在参加「金石计划 . 瓜分6万现金大奖」

王志远,微医前端技术部

前言

​ 根据前文,我们已经学习了【字符组】和【量词】的概念,就像一门编程语言,有组成物料还不够,自然还需要一些逻辑判断,在正则中也存在【逻辑元字符】这一概念。

​ 此外,我们知道编程里都有运算符权重的问题,比如先乘除后加减,在正则中如何提升多个元字符的优先级使之成为一个整体呢?同样是括号,只不过在正则中它被称为分组。

逻辑元字符

|号:或逻辑

某个资源可能以 http:// 开头,或者 https:// 开头,也可能以 ftp:// 开头,那么资源的 协议部分,我们可以使用 (https?|ftp):// 来表示。

分组

在正则中存在分组的概念,主要有两点作用:整体和复用。

需要注意的是:括号的权重大于 | 符号,所以可以用于分支时的结构划分

  • 分组的核心概念分析
  • 分组引用和分组反向引用
  • 命名分组

核心概念分析

整体

​ 代表避免语义分析有歧义,如【匹配 15 位数字或 18 位数字】,这时如果写出这样的正则/\d{15}\d{3}?/;后面的\d{3}?将代表懒惰模式匹配,这个正则会只匹配 18 位数字而非 15 位

测试正则: /\d{15}\d{3}?/

​ 这里就存在确定\d{3}是一个整体的需求,这可以使用分组实现

测试正则: /\d{15}(\d{3})?/

复用

​ 有些时候,我们也会需要用到之前匹配到的结果,如【查看文本中的连续重复单词】,解决思路就变成了

  1. 写出匹配单个单词的正则

  2. 使用之前的结果进行再次匹配

    第二点,就是通过分组实现的;先了解下基础概念

语法: 定义使用() ,正则中访问使用\编号,方法中访问使用$编号

作用: 用于分组,被括号括起来的部分默认将被保存为子组,正则中可以通过子组编号访问,子组编号从一递增,也可以用语法(?:)从而不保存子组,避免占用编号。

分组引用

在一次成功的匹配中,每一个括号包裹的结构都是一个分组,将会存储在一个空间内容,由 RegExp 的静态属性11、2...访问

分组引用

​ 假定分组编号为number,则可以使用\number进行引用

多编号情况

左括号是第几个,那就是第几个分组

不保存子组

使用此语法后不会为这个子组分配编号

替换功能

命名分组

​ V8 目前已经完全实现了命名捕获分组的提案 tc39.github.io/proposal-re…

基础概念

语法: 定义使用(?<name>) ,正则中访问使用\k<name>,方法中访问使用$<name>

作用: 用于命名分组,不再使用编号访问而是直接通过分组变量名访问,更加准确

API 结合解构赋值

​ 在 js 关于正则的方法中,如果存在命名分组,会存在groups属性,里面存放着每个命名分组的名称以及它们匹配到的值;结合解构赋值,会有很神奇的功效;

在 exec() 和 match() 中的使用:

​ exec() 和 match() 方法返回的匹配结果数组上多了一个 groups 属性,里面存放着每个命名分组的名称以及它们匹配到的值

const {day, month, year} = "04-25-2017".match(/(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})/).groups 

在 replace(/.../, replacement) 中的使用:

​ 当replacement为函数时,在实参列表的最末尾,多传了一个 groups 对象

"04-25-2017".replace(/(?<month>\d{2})-(?<day>\d{2})-(?<year>\d{4})/, (...args) => {
  const groups = args.slice(-1)[0]
  const {day, month, year} = groups
  return `${day}-${month}-${year}`
}) 

模式

在正则中,存在模式的概念,主要是改变元字符的匹配行为,提供对一些特殊情况的处理,目前有四种:

  • 不区分大小写模式
  • 点通配模式
  • 多行匹配模式
  • 注释模式

![](/Users/wzyan/Library/Application Support/typora-user-images/image-20211213230142906.png)

我们来逐一了解

不区分大小写模式(Case-Insensitive)

语法: /(?i)reg/ 对应 js 为 /reg/i

注意点:

  1. 不区分大小写模式的指定方式,使用模式修饰符 (?i);
  2. 修饰符如果在括号内,作用范围是这个括号内的正则,而不是整个正则;

作用: 忽略大小写进行匹配

正则: /(?i)(cat) \1/ 对应 js 为 /(cat) \1/i

如果这时候我们希望重复单词间保持大小写完全一致,可以使用如下正则

正则: /((?i)cat) \1/ 对应 js 为 暂无

点通配模式(单行匹配模式 -- Single Line)

语法: /(?s)reg/ 对应 js 为暂无

注意点:

作用: 使得.元字符可以匹配包括换行在内的所有字符

多行匹配模式

语法: /(?m)reg/ 对应 js 为/reg/m

注意点:

作用: 使得^$可以匹配上每行的开头或结尾

使用前正则: /^the|cat$/

使用后正则: /(?m)^the|cat$/ 对应 js 为/^the|cat$/m

注释模式

语法: /(?#)reg/ 对应 js 为 暂无

注意点:

作用: 使得正则支持添加备注信息

使用正则案例: /(\w+)(?#word) \1(?#word repeat again)/