正则表达式进阶(三):递归模式与条件匹配的艺术
在正则表达式的高级应用中,递归模式和条件匹配是处理复杂嵌套结构和动态模式的利器。它们突破了传统正则表达式的线性匹配局限,能够应对嵌套括号、HTML标签、上下文依赖等复杂场景。本文将详细介绍递归模式((?>...)
、 (?R)
等)和条件匹配(如 (?(condition)then|else)
),并通过丰富示例展示其在实际开发中的强大能力。
1. 递归模式:处理嵌套结构
递归模式允许正则表达式在匹配过程中“调用自身”,非常适合处理嵌套结构,如括号配对、XML/HTML标签嵌套等。递归模式依赖于特定正则引擎(如 PCRE、Perl),常用构造包括 (?R)
和命名子组递归。
1.1 基本递归:(?R)
(?R)
表示整个正则表达式递归调用自身,常用于匹配简单的嵌套结构。
示例:匹配嵌套括号
假设需要匹配合法的嵌套括号,如 (a)
、(a(b))
。正则表达式如下:
/\((?:[^()]+|(?R))*\)/
文本:
(a)
(a(b))
((c)d)
(a(b)c
代码(Perl):
$ perl -nle 'print $& if /\((?:[^()]+|(?R))*\)/' input.txt
输出:
(a)
(a(b))
((c)d)
解析:
\(
:匹配开括号。(?:[^()]+|(?R))*
:非捕获组,匹配:[^()]+
:非括号字符序列。|(?R)
:递归调用整个表达式,处理嵌套括号。
\)
:匹配闭括号。- 整体确保括号配对正确。
应用场景
- 代码解析:匹配编程语言中的嵌套括号(如函数调用)。
- 数学表达式:验证括号配对的合法性。
1.2 命名子组递归
对于更复杂的嵌套结构,可以使用命名子组递归(如 (?&name)
)来提高可读性和控制递归范围。
示例:匹配嵌套HTML标签
假设需要匹配嵌套的 <div>
标签:
/<div>(?:(?!</?div>).|(?R))*<\/div>/
文本:
<div>text</div>
<div>text<div>nested</div></div>
<p>text</p>
代码(Perl):
$ perl -nle 'print $& if /<div>(?:(?!<\/?div>).|(?R))*<\/div>/' input.txt
输出:
<div>text</div>
<div>text<div>nested</div></div>
解析:
<div>
:匹配开标签。(?:(?!</?div>).|(?R))*
:匹配非<div>
或</div>
的字符,或递归调用整个模式。<\/div>
:匹配闭标签。(?!</?div>)
防止匹配到其他<div>
标签,确保嵌套正确。
应用场景
- HTML/XML解析:提取嵌套标签结构。
- 配置文件校验:验证嵌套结构的完整性。
注意
- 递归模式对正则引擎要求较高,JavaScript 不支持
(?R)
,需使用 PCRE 或 Perl。 - 复杂递归可能导致性能问题,建议限制嵌套深度。
2. 条件匹配:动态模式选择
条件匹配允许正则表达式根据上下文动态选择匹配模式,格式为 (?(condition)then|else)
。它依赖于前向捕获组或断言,适用于需要根据上下文调整匹配逻辑的场景。
2.1 基于捕获组的条件匹配
(?(n)then|else)
检查第 n
个捕获组是否匹配成功,决定执行 then
或 else
分支。
示例:匹配电话号码格式
假设需要匹配电话号码,格式为 (123) 456-7890
或 123-456-7890
,要求括号要么都出现,要么都不出现:
/(\()?(\d{3})(?(1)\)|-)\d{3}-\d{4}/
文本:
(123) 456-7890
123-456-7890
(123-456-7890
123 456-7890
代码(Perl):
$ perl -nle 'print $& if /(\()?(\d{3})(?(1)\)|-)\d{3}-\d{4}/' input.txt
输出:
(123) 456-7890
123-456-7890
解析:
(\()?)
:捕获组 1,匹配可选的开括号。(\d{3})
:捕获组 2,匹配三位数字。(?(1)\)|-)
:条件匹配:- 如果捕获组 1(开括号)存在,则匹配
\)
. - 否则匹配
-
。
- 如果捕获组 1(开括号)存在,则匹配
\d{3}-\d{4}
:匹配剩余部分。
应用场景
- 数据格式校验:验证一致的格式(如电话号码、日期)。
- 日志解析:根据前缀动态匹配不同模式。
2.2 基于断言的条件匹配
(?(?=condition)then|else)
使用前向断言作为条件,增加灵活性。
示例:匹配特定前缀的字符串
假设需要匹配以“ERROR”开头的字符串后接数字,以“INFO”开头的后接字母:
/^(ERROR|INFO)(?(?=ERROR)\d+|[a-z]+)/
文本:
ERROR123
INFOabc
ERRORabc
INFO123
代码(Perl):
$ perl -nle 'print $& if /^(ERROR|INFO)(?(?=ERROR)\d+|[a-z]+)/' input.txt
输出:
ERROR123
INFOabc
解析:
^(ERROR|INFO)
:捕获组 1,匹配前缀。(?(?=ERROR)\d+|[a-z]+)
:条件匹配:- 如果前向断言
(?=ERROR)
成功(即以“ERROR”开头),匹配\d+
。 - 否则匹配
[a-z]+
。
- 如果前向断言
应用场景
- 日志分类:根据日志级别动态提取内容。
- 协议解析:根据头部选择不同的解析规则。
3. 综合示例:递归与条件匹配结合
假设需要解析一个嵌套的JSON-like结构,要求键以引号包裹,值可以是字符串或嵌套对象:
/"[^"]+"\s*:\s*(?:"[^"]+"|{(?:(?R)(?:,\s*(?R))*?)?})/
文本:
"name": "John"
"data": {"age": "30", "city": "NY"}
"invalid": [1,2,3]
代码(Perl):
$ perl -nle 'print $& if /"[^"]+"\s*:\s*(?:"[^"]+"|{(?:(?R)(?:,\s*(?R))*?)?})/' input.txt
输出:
"name": "John"
"data": {"age": "30", "city": "NY"}
解析:
"[^"]+"
:匹配键(如"name"
)。\s*:\s*
:匹配键值分隔符:
。(?:"[^"]+"|...)
:值可以是:"[^"]+"
:字符串值。{(?:(?R)(?:,\s*(?R))*?)?}
:递归匹配嵌套对象,允许空对象{}
或多个键值对。
条件匹配扩展:如果需要确保键以特定前缀(如 "data_"
)开头,可以添加条件:
/("data_[^"]+"|"[^"]+")\s*:\s*(?(1){(?:[^}]+|(?R))*}|[^,]+)/
4. 总结与进阶技巧
递归模式和条件匹配将正则表达式的能力推向新高度,特别适合处理嵌套结构和动态模式。以下是使用建议:
- 明确需求:递归模式适合嵌套结构,条件匹配适合上下文依赖场景。
- 优化性能:避免过度递归或复杂条件,必要时限制匹配范围(如使用
(?>...)
原子组)。 - 测试充分:复杂正则易出错,需用多种边界用例验证。
- 引擎兼容性:递归和条件匹配依赖 PCRE/Perl,JavaScript 不支持,需确认环境。
通过掌握递归模式和条件匹配,开发者可以轻松应对复杂的文本解析任务,如解析嵌套数据、验证协议格式等。这些技术与零宽断言(前文所述)结合,能构建出功能强大且优雅的正则表达式。
展望:下一篇文章将探讨正则表达式的性能优化与调试技巧,教你如何编写高效且易维护的正则表达式,敬请期待!
相关文章:
正则表达式进阶(三):递归模式与条件匹配的艺术
在正则表达式的高级应用中,递归模式和条件匹配是处理复杂嵌套结构和动态模式的利器。它们突破了传统正则表达式的线性匹配局限,能够应对嵌套括号、HTML标签、上下文依赖等复杂场景。本文将详细介绍递归模式((?>...)、 (?R) 等࿰…...

ubuntu环境下 基于Python 打包的 批量命令行可视化操作工具 GUI
文章目录 一.需求:二.原理支撑:三.简单Demo四.封装成GUI1.依赖库2.代码 五.打包成可执行文件六.命令行的配置七.运行效果 一.需求: 作为测试工程师,为了到现场高效的调试,部署工作,需要一个可视化的工具&a…...
docker介绍与常用命令汇总
docker简介 docker是什么? Docker 是一个开源的应用容器引擎,它可以让开发者将应用与运行环境打包成一个标准的、可移植的容器(Container),在任何地方都可以快速部署和运行,无需关心底层环境是否一致。 …...
[创业之路-369]:企业战略管理案例分析-9-战略制定-差距分析的案例之华为
一、综合案例 在战略制定中,华为通过差距分析明确战略方向,以应对市场挑战和实现长期发展目标。 以下为具体案例与分析: 1、案例背景 华为在通信设备领域崛起过程中,始终将差距分析作为战略制定的核心环节。面对国际竞争对手&…...

谷歌宣布推出 Android 的新安全功能,以防止诈骗和盗窃
在上周二的 Android Show 上,也就是Google I/O 开发者大会之前,谷歌宣布了 Android 的全新安全和隐私功能。这些新功能包括对通话、屏幕共享、消息、设备访问和系统级权限的全新保护。谷歌希望通过这些功能保护用户免遭诈骗,在设备被盗或被攻…...

Qt/C++编写音视频实时通话程序/画中画/设备热插拔/支持本地摄像头和桌面
一、前言 近期有客户提需求,需要在嵌入式板子上和电脑之间音视频通话,要求用Qt开发,可以用第三方的编解码组件,能少用就尽量少用,以便后期移植起来方便。如果换成5年前的知识储备,估计会采用纯网络通信收发…...
Android trace presentFence屏幕显示的帧
Android trace presentFence屏幕显示的帧 presentFence :当帧成功显示到屏幕时,present fence就会signal。 FrameMissed/GpuFrameMissed/HwcFrameMissed表示上一次合成的结果,当SurfaceFlinger合成后显示到屏幕上,present fence就…...
Spring是如何实现scope作用域支持
众所周知在Spring的Bean当中是存在两种作用域的,即单例模式与多例模式,可通过scope来指定 下面就是注册一个多例Bean <bean id"people" class"org.qlspringframework.beans.ioc.bean.People" scope"prototype"> …...
Helm Chart 中配置多个 Docker Registry 地址以实现备用访问
在 Helm Chart 中配置多个 Docker Registry 地址以实现备用访问,可以通过以下几种方式实现: 1. 在 values.yaml 中定义多个 Registry 在 values.yaml 中定义主 Registry 和备用 Registry,以便在部署时灵活切换: # values.yaml …...
FreeSWITCH rtcp-mux 测试
rtcp 跟 rtp 占用同一个端口,这就是 rtcp 复用 Fs 呼出是这样的: originate [rtcp_muxtrue][rtcp_audio_interval_msec5000]user/1001 &echo 需要同时指定 rtcp_audio_interval_msec,否则 rtcp_mux 不能生效 Fs 呼入不需要配置…...

c++ 类的语法4
测试析构函数、虚函数、纯虚函数: void testClass5() {class Parent {public:Parent(int x) { cout << "Parent构造: " << x << endl; }~Parent() {cout << "调用Parent析构函数" << endl;}virtual string toSt…...

NMOS和PMOS的区别
1 区分NMOS和PMOS:衬底箭头指向G级的是NMOS,衬底箭头背向G级的是PMOS 2 区分D和S级:针对NMOS,体二极管的正方向为S级;针对PMOS,体二极管正的方向为D级 3 区分电流方向:针对NMOS,电…...

java云原生实战之graalvm 环境安装
windows环境安装 在Windows环境下安装GraalVM并启用原生镜像功能时,需要Visual Studio的组件支持。具体要点如下: 核心依赖: 需要安装Visual Studio 2022或更新版本,并确保勾选以下组件: "使用C的桌面开发"…...

2025年电工杯新规发布-近三年题目以及命题趋势
电工杯将于2025.5.23 周五早八正式开赛,该竞赛作为上半年度竞赛规模最大的竞赛,因免报名费、一级学会承办等因素,被众多高校认可。本文将在从2025年竞赛新规、历史赛题选题分析、近年优秀论文分享、竞赛模板分析等进行电工杯备赛,…...
python打卡day30@浙大疏锦行
知识点回顾: 导入官方库的三种手段导入自定义库/模块的方式导入库/模块的核心逻辑:找到根目录(python解释器的目录和终端的目录不一致) 作业:自己新建几个不同路径文件尝试下如何导入 具体操作步骤: 在桌面…...

替换word中的excel
PostMapping("/make/report/target/performance/first") public AjaxResult makeTargetReportFirst(RequestBody MakeReportDTO makeReportDTO) {Map<String, String> textReplaceMap new HashMap<>();// 替换日期LocalDateTime nowData LocalDateTime…...

大模型服务如何实现高并发与低延迟
写在前面 大型语言模型(LLM)正以前所未有的速度渗透到各行各业,从智能客服、内容创作到代码生成、企业知识库,其应用场景日益丰富。然而,将这些强大的 AI 能力转化为稳定、高效、可大规模应用的服务,却面临着巨大的挑战,其中高并发处理能力和低响应延迟是衡量服务质量的…...
异丙肌苷市场:现状、挑战与未来展望
摘要 本文聚焦异丙肌苷市场,深入分析了其市场规模与增长趋势、应用价值与市场驱动因素、面临的挑战以及竞争格局。异丙肌苷作为一种具有重要应用价值的改性核苷衍生物,在药物研发和治疗领域展现出潜力,但市场发展也面临诸多挑战。文章最后为…...

OBS Studio:windows免费开源的直播与录屏软件
OBS Studio是一款免费、开源且跨平台的直播与录屏软件。其支持 Windows、macOS 和 Linux。OBS适用于,有直播需求的人群或录屏需求的人群。 Stars 数64,323Forks 数8413 主要特点 推流:OBS Studio 支持将视频实时推流至多个平台,如 YouTube、…...
[ 计算机网络 ] | 宏观谈谈计算机网络
(目录占位) 网络间通信,本质是不同的两个用户通信;本质是两个不同主机上的两个进程间通信。 因为物理距离的提升,就衍生出了很多问题。TCP/IP协议栈 / OSI七层模型,将协议分层,每一层都是为了…...

经典面试题:TCP 三次握手、四次挥手详解
在网络通信的复杂架构里,“三次握手”与“四次挥手”仿若一座无形的桥梁,它们是连接客户端与服务器的关键纽带。这座“桥梁”不仅确保了连接的稳固建立,还保障了连接的有序结束,使得网络世界中的信息能够顺畅、准确地流动。 在面…...

高光谱数据处理技术相关
一、Savitzky-Golay(SG)平滑 1. 基本概念 Savitzky-Golay(SG)平滑是一种基于局部多项式拟合的卷积算法,主要用于信号处理(如光谱、色谱数据)的去噪和平滑。其核心思想是通过滑动窗口内的多项式拟合来保留信号的原始特征(如峰形、宽度),同时抑制高频噪声。 2. 技术原…...
【动态规划】P10988 [蓝桥杯 2023 国 Python A] 走方格|普及+
本文涉及知识点 C动态规划 P10988 [蓝桥杯 2023 国 Python A] 走方格 题目描述 给定一个 N N N 行 N N N 列的方格,第 i i i 行第 j j j 列的方格坐标为 ( i , j ) (i, j) (i,j),高度为 H i , j H_{i,j} Hi,j。小蓝从左上角坐标 ( 0 , 0 ) …...
Rocketmq leader选举机制,通过美国大选解释
通过2020年美国大选的比喻,可以形象地解释RocketMQ的Leader选举机制(以DLedger模式为例)。我们将美国大选中的关键角色和流程映射到RocketMQ的集群中,帮助理解其工作原理。 1. 角色类比 美国大选RocketMQ DLedger集群说明选民&am…...

机器视觉的PVC卷对卷丝印应用
在现代工业制造领域,PVC卷对卷丝印工艺凭借其高效、灵活的特点,广泛应用于广告制作、包装印刷、电子产品装饰等多个行业。然而,在高速连续的丝印过程中,如何确保印刷图案的精准定位、色彩一致性以及质量稳定性,一直是困…...
利用 SQL Server 作业实现异步任务处理,简化系统架构
在现代企业系统中,异步任务是不可或缺的组成部分,例如: 电商系统中的订单超时取消; 报表系统中的异步数据导出; CRM 系统中的客户积分计算。 传统的实现方式通常涉及引入消息队列(如 RabbitMQ、Kafka&a…...

LabVIEW数据库使用说明
介绍LabVIEW如何在数据库中插入记录以及执行 SQL 查询,适用于对数据库进行数据管理和操作的场景。借助 Database Connectivity Toolkit,可便捷地与指定数据库交互。 各 VI 功能详述 左侧 VI 功能概述:实现向数据库表中插入数据的操作。当输入…...
MATLAB实现GAN用于图像分类
生成对抗网络(GAN)是一种强大的生成模型,由生成器(Generator)和判别器(Discriminator)组成。生成器用于生成图像,判别器用于判断图像是真实的还是生成的。在MATLAB中实现GAN用于图像…...

25考研经验贴(11408)
声明:以下内容都仅代表个人观点 数学一(130) 25考研数学一难度介绍:今年数学一整体不难,尤其是选填部分,大题的二型线面和概率论大题个人感觉比较奇怪,其他大题还是比较容易的。.26如何准备&a…...

java中的Filter使用详解
Filter(过滤器)是 Java Web 开发的核心组件之一,用于在请求到达 Servlet 或响应返回客户端之前进行拦截和处理。以下是其核心功能、使用方法和实际场景的详细解析: 一、Filter 的作用与原理 核心作用 Filter 充当请求与响应之间的…...