【0基础教程】Javascript 正则表达式里的分组捕捉 Capturing Groups 使用方法及原理

news2024/10/6 6:05:03

在这里插入图片描述

一、从最简单开始

现有一个字符串: “1-apple”
需要解析出 1 和 apple 来,对应的正则表达式很简单: ^(\d)-(.+)$
其中,
^ 表示字符串的开始,然后一个圆括号包裹的内容表示一个"组":(\d) 表示一组数字, (.+) 表示是一组任意值;$ 表示字符串的结束。
对应的代码:

        const str = "1-apple"
        const regexp = /^(\d)-(.+)$/
        let match = regexp.exec(str)
        console.log(match[0])
        console.log(match[1])
        console.log(match[2])

注意,尽管只有两个括号,但是正则的返回值却有三个:

match[0] = 1-apple
match[1] = 1
match[2] = apple

match[0] 返回的是一个完整匹配,其值就是str本身。显然在这个例子中 match[0] 并没有什么用,因为我们真正要解析的内容是 match[1] 和 match[2]。


二、重复模式分组

如果字符串中出现多次重复的模式( pattern ),比如碰到这种情况时:
1-apple
2-orange
3-pear
以上三行文字,尽管内容不同,但规律是一样的,即每一行都是:(数字)-(任意值)
因此我们可以使用一个正则表达式来匹配这3行文字,注意后面需要增加 gm 标识符,(g代表global,m代表multi line),代码如下:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm   //注意:和上例相比,唯一的区别是后面加了gm标志
        let match = regexp.exec(str)
        console.log(match[0])
        console.log(match[1])
        console.log(match[2])

运行结果:

match[0] = 1-apple
match[1] = 1
match[2] = apple

只解析了 1-apple 出来,那么我们如何解析出 2-orange3-pear 呢?
让我们修改一下代码:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm
        let match
        match = regexp.exec(str) // 第1次触发
        console.log(match[0])
        console.log(match[1])
        console.log(match[2])

        match = regexp.exec(str) // 第2次触发
        console.log(match[0])
        console.log(match[1])
        console.log(match[2])

        match = regexp.exec(str) // 第3次触发
        console.log(match[0])
        console.log(match[1])
        console.log(match[2])

运行结果:

1-apple
1
apple

2-orange
2
orange

3-pear
3
pear

在这个例子里,我们连续三次触发了match = regexp.exec(str) 这行语句,
事实上,尽管语句完全一样,但是每一次match的返回值都不同。在带有 gm 标识符时,.exec方法会将当前匹配值的首字符位置保存在 index 变量里(注:不带 gm 标识符没有这个变量),当下一次触发.exec的时候,index 并不是从0开始搜索,而是从第一次匹配完成之后的位置进行第二次匹配,如此反复,直至将整个字符匹配完成为止。

知道了 .exec 这个方法可以反复执行这个小秘密之后,将代码再改改就很简单了:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm   //注意:和上例相比,唯一的区别是后面加了gm标志
        let match
        while ((match = regexp.exec(str)) !== null) {
            console.log('index = ', match.index)
            console.log('result = ', match[0], match[1], match[2])
        }

运行结果:

index = 0
result = 1-apple 1 apple
index = 8
result = 2-orange 2 orange
index = 17
result = 3-pear 3 pear

或者,我们还可以将结果 push 到一个二维数组里以方便使用:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm 
        let match
        let matches = []
        while ((match = regexp.exec(str)) !== null) {
            matches.push(match)
        }
        console.log(matches[0][1]) // 显示:1
        console.log(matches[0][2]) // 显示:apple
        console.log(matches[1][1]) // 显示:2
        console.log(matches[1][2]) // 显示:orange
        console.log(matches[2][1]) // 显示:3
        console.log(matches[2][2]) // 显示:pear

三、matchAll 登场

如果你不喜欢while循环方式,还可以使用 matchAll ,就可以不必使用 while 循环加 exec 方式。使用 matchAll 会得到一个迭代器的返回值,配合 for…of, array spread, 或者 Array.from() 可以更方便实现功能。

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm

        const matches = str.matchAll(regexp) // 采用matchAll进行匹配

        for (const match of matches) { // 采用 for of 方式读取
            console.log('index = ', match.index)
            console.log('result = ', match[0], match[1], match[2])
        }

这段代码效果和上例完全一样。

此外,我们也可以用Array.from() 实现同样的效果:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm

        const matches = str.matchAll(regexp) 
        Array.from(matches, (match) => { // 采用 Array.from方式读取
            console.log('index = ', match.index)
            console.log('result = ', match[0], match[1], match[2])
        })

或者更简单的ES6的“三个点”语法( array spread ):

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm

        const matches = [...str.matchAll(regexp)] // 采用 ... 方式展开str.matchAll(regexp)

		// 遍历数组
        for (let i = 0; i < matches.length; i++) {
            console.log('index = ', matches[i].index)
            console.log('result = ', matches[i][0], matches[i][1], matches[i][2])
        }

三个点称为 “array spread” 或者“展开语法”,它的作用很多很杂,没有展开语法的时候,只能组合使用 push, splice, concat 等方法,来将已有数组元素变成新数组的一部分。有了展开语法,通过字面量方式,构造新数组会变得更简单、更优雅,比如:

        const str = "1-apple\n2-orange\n3-pear"
        const regexp = /^(\d)-(.+)$/gm

        const matches = [...str.matchAll(regexp)] // 采用 ... 方式展开str.matchAll(regexp)

        console.log(matches[0][1]) // 显示:1
        console.log(matches[0][2]) // 显示:apple
        console.log(matches[1][1]) // 显示:2
        console.log(matches[1][2]) // 显示:orange
        console.log(matches[2][1]) // 显示:3
        console.log(matches[2][2]) // 显示:pear

三个点 “…” 将 str.matchAll(regexp) 展开之后,我们将直接获得一个二维数组,不需要额外执行 push 操作,与前面介绍的办法相比,更简单、直观。


四、后记

本文只列举了非常简单的关于正则分组的基础案例,进一步研究可以阅读以下资料:

【matchAll()详解】:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String/matchAll

【array spread 展开语法详解】:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/652486.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【深度学习】2-1 神经网络 - 激活函数

激活函数 将输入信号的总和转换为输出信号&#xff0c;一般称为激活函数&#xff08;activation function&#xff09;。激活函数作用在于决定如何来激活输入信号的总和。 对激活函数&#xff0c;一般要求&#xff1a; 非线性&#xff1a;为提高模型的学习能力&#xff0c;如…

Nginx reuseport导致偶发性卡顿

背景 从2018年开始&#xff0c;我们有个业务陆续接到反馈 Nginx 线上集群经常出现不响应或者偶发性的“超慢”请求。这种卡顿每天都有少量出现。而只有多个集群中的一个出现&#xff0c;其他压力更大的集群皆未出现。 业务结构比较简单&#xff1a;LVS->Nginx->后端&…

Advanced-C.01.基础知识

C语言程序设计概述 一个简单句的C程序 #include <stdio.h> int main(){printf("This is a C program.\n");retrun 0; }C程序的执行过程 数据单位 bit&#xff1a;位&#xff0c;计算机中最小的数据单位Byte&#xff1a;字节&#xff0c;计算机中信息组织和存…

C++ 搜索二叉树

目录 C 搜索二叉树一. 介绍二.简单实现搜索二叉树1. 基本框架2. 插入节点a. 图示&#xff1a;b. 递归实现&#xff1a;c. 非递归&#xff1a; 3. 删除节点a. 图示&#xff1a;b. 递归实现&#xff1a;c. 非递归&#xff1a; 三. 小结 C 搜索二叉树 又名&#xff1a;二叉搜索树…

bean的三种实例化方式

实例化bean的三种方式&#xff0c;构造方法,静态工厂和实例工厂 构造方法实例化&#xff08;常用&#xff09; 步骤1&#xff1a;准备一个BookDao和BookDaoImpl类 public interface BookDao {public void save(); } ​ public class BookDaoImpl implements BookDao {public…

Vue中如何进行表单图片裁剪与预览

Vue中如何进行表单图片裁剪与预览 在前端开发中&#xff0c;表单提交是一个常见的操作。有时候&#xff0c;我们需要上传图片&#xff0c;但是上传的图片可能会非常大&#xff0c;这会增加服务器的负担&#xff0c;同时也会降低用户的体验。因此&#xff0c;我们通常需要对上传…

Python:关于flask框架的flask_scrip._compat

关于flask框架的flask_scrip._compat compat是什么源码Flask版本书写不同 compat是什么 compat 英文单词同胞的意思 compat的功能是在py的不同版本之间做兼容处理 一些py2/py3兼容性支持基于精简版的six&#xff0c;因此我们不必依赖于它的特定版本。 源码 # -*- coding: u…

使用芯片和贴片天线解决多频带射频问题

智能手机和可穿戴电子设备等手持和便携式无线产品依赖可置入设备的微型芯片、贴片和印制线天线。尽管这些小型器件解决了在小尺寸系统中携带多频带天线阵列的问题&#xff0c;但它们也引入了辐射效率下降、阻抗匹配以及与附近物体和人体的交互等相关问题。 为解决这些问题&…

ASO优化之如何降低应用的卸载率

不管是苹果应用商店&#xff0c;还是国内的安卓市场和国外的Google Play&#xff0c;拥有超过200万个应用&#xff0c;每个应用都面临着众多的竞争对手&#xff0c;当应用在承诺之后没有及时兑现可以提供的功能&#xff0c;就会面临被卸载的风险。 对应用在不同平台的应用商店…

chatgpt赋能python:Python数据类型的确定方法

Python数据类型的确定方法 在Python中&#xff0c;一个变量可以保存任何类型的数据。数据类型是指数据的种类和形式。在使用Python时&#xff0c;数据类型通常是自动推断的&#xff0c;但有时我们需要手动确定数据类型。本文介绍了Python中确定变量数据类型的几种方法。 使用…

如何部署免交互脚本

目录 一、免交互 什么是免交互 Here Document免交互 二、Expect概述 expect sed命令 三、如何用ssh实现免交互 四、监控硬盘实现免交互 五、创建硬盘分区如何实现免交互 一、免交互 什么是免交互 交互&#xff1a;需要人工发出指令&#xff0c;来控制程序的运行&…

走向实用的AI编解码

基于AI的端到端数据压缩方法受到越来越多的关注&#xff0c;研究对象已经包括图像、视频、点云、文本、语音和基因组等&#xff0c;其中AI图像压缩的研究最为活跃。图像编解码的研究和应用历史悠久&#xff0c;AI方法要达到实用&#xff0c;需要解决诸多问题才能取得相比于传统…

金融大数据平台是怎么构建的?

大数据对银行业的价值不言而喻。 在业务上,如何去挖掘客户的内在需求,为客户提供更有价值的服务是目前金融机构的战略转型和业务创新的关键。大数据技术正是金融机构深挖数据资产、实现差异化竞争、推动业务创新的重要工具。 在运营上,通过大数据应用和分析,金融机构能够定位…

利用事务消息实现分布式事务

什么是事务 什么是事务呢&#xff1f;事务是并发控制的单位&#xff0c;是用户定义的一个操作序列。有四个特性(ACID)&#xff1a; 原子性(Atomicity)&#xff1a; 事务是数据库的逻辑工作单位&#xff0c;事务中包括的诸操作要么全做&#xff0c;要么全不做。一致性(Consist…

深入探究kubernetes resources - Part 2

你以为CPU请求只是用来调度的吗&#xff1f; 再想一想。 引入 CPU 份额&#xff0c;并为消除限制奠定基础&#xff01; 了解 CPU 请求 在上一篇文章中&#xff0c;我谈到了 Kubernetes 资源管理的基础。 在这篇文章中&#xff0c;我们将深入探讨当我们将 CPU 请求配置到 pod 的…

3D建模Cocos Creator3D:发射器模块(ShapeModule)

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 发射器模块(ShapeModule) 公有属性&#xff1a; 属性作用position相对于挂载节点的位置rotation相对于挂载节点的旋转scale相对于挂载节点的缩放sphericalDirectionAmount表示当前…

ESP32(Micro Python)LVGL 两个动画程序

本次发布两个程序&#xff0c;仪表盘动画程序对刻度数量等参数进行调整&#xff0c;方便布置多个小尺寸仪表盘&#xff1b;进度条动画程序展示了多个进度条的排列方式。 仪表盘程序 import lvgl as lv import time from espidf import VSPI_HOST from ili9XXX import ili93…

人机交互学习-6 交互式系统的设计

交互式系统的设计 设计框架定义外形因素和输入方法定义功能和数据元素决定功能组合层次勾画大致的设计框架构建关键情景场景剧本通过验证性的场景剧本来检查设计 设计策略删除组织隐藏转移简化设计策略的组合 设计中的折中个性化和配置本地化和国际化审美学与实用性 软件设计的…

Golang context 实现原理与源码分析

0 context入门介绍 context是Golang应用开发常用的并发控制技术&#xff0c;主要在异步场景中用于实现并发协调以及对 goroutine 的生命周期控制&#xff0c;它与WaitGroup最大的不同点是context对于派生goroutine有更强的控制力&#xff0c;它可以控制多级的goroutine。 con…

DataGrip使用技巧

DataGrip介绍 DataGrip是JetBrains提供的面向开发人员的数据库管理产品。提供智能查询控制台、高效的架构导航、智能SQL补全等功能。 同类的产品有navicat、dbeaver。本文中使用的DataGrip版本为2023.1 显示数据库其他类型的数据库结构 DataGrip中如果某类型数据库结构数量为…