【文本处理】正则表达式

news2024/9/29 7:25:04

一、简介

正则表达式,又称规则表达式,(Regular Expression,在代码中常简写为regex、regexp或RE),是一种文本模式,包括普通字符(例如,a 到 z 之间的字母)和特殊字符(称为"元字符"),是计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式(规则)的文本。

二、起源

正则表达式的“鼻祖”或许可一直追溯到科学家对人类神经系统工作原理的早期研究。美国新泽西州的Warren McCulloch和出生在美国底特律的Walter Pitts这两位神经生理方面的科学家,研究出了一种用数学方式来描述神经网络的新方法,他们创造性地将神经系统中的神经元描述成了小而简单的自动控制元,从而作出了一项伟大的工作革新。

在1951 年,一位名叫Stephen Kleene的数学科学家,他在Warren McCulloch和Walter Pitts早期工作的基础之上,发表了一篇题目是《神经网事件的表示法》的论文,利用称之为正则集合的数学符号来描述此模型,引入了正则表达式的概念。正则表达式被作为用来描述其称之为“正则集的代数”的一种表达式,因而采用了“正则表达式”这个术语。

之后一段时间,人们发现可以将这一工作成果应用于其他方面。1968年,Unix之父Ken Thompson就把这一成果应用于计算搜索算法的一些早期研究。Ken Thompson将此符号系统引入编辑器QED,然后是Unix上的编辑器ed,并最终引入grep。Jeffrey Friedl 在其著作《Mastering Regular Expressions (2nd edition)》(中文版译作:精通正则表达式,已出到第三版)中对此作了进一步阐述讲解。

自此以后,正则表达式被广泛地应用到各种UNIX或类似于UNIX的工具中,如大家熟知的Perl。Perl的正则表达式源自于Henry Spencer编写的regex,之后已演化成了pcre(Perl兼容正则表达式Perl Compatible Regular Expressions),pcre是一个由Philip Hazel开发的、为很多现代工具所使用的库。正则表达式的第一个实用应用程序即为Unix中的 qed 编辑器。

三、引擎

正则引擎主要可以分为两大类:一种是确定型有穷自动机(Deterministic finite automaton, DFA),一种是非确定型有穷自动机(Non-deterministic finite automaton,NFA)。这两种引擎都有了很久的历史,当中也由这两种引擎产生了很多变体。于是POSIX的出台规避了不必要变体的继续产生。这样一来,主流的正则引擎又分为3类:一、DFA,二、传统型NFA,三、POSIX NFA。

   - **DFA引擎**:

DFA引擎对每一个字符只进行一次判断。它比较快速且其性能不受正则表达式复杂度的影响,但它不支持某些高级匹配特性,例如捕获组和回溯引用。
DFA 引擎在线性时状态下执行,因为它们不要求回溯(并因此它们永远不测试相同的字符两次)。DFA 引擎还可以确保匹配最长的可能的字符串。但是,因为 DFA 引擎只包含有限的状态,所以它不能匹配具有反向引用的模式;并且因为它不构造显示扩展,所以它不可以捕获子表达式。

   - **NFA引擎**:

NFA引擎可以进行回溯,支持更复杂的正则功能,如前述的捕获组、非贪婪量词以及前后断言等。大部分现代编程语言使用这种引擎。然而,当正则表达式特别复杂时,NFA引擎可能导致性能下降,因为它会尝试所有可能的路径来匹配一个字符串。

传统的 NFA 引擎运行所谓的“贪婪的”匹配回溯算法,以指定顺序测试正则表达式的所有可能的扩展并接受第一个匹配项。因为传统的 NFA 构造正则表达式的特定扩展以获得成功的匹配,所以它可以捕获子表达式匹配和匹配的反向引用。但是,因为传统的 NFA 回溯,所以它可以访问完全相同的状态多次(如果通过不同的路径到达该状态)。因此,在最坏情况下,它的执行速度可能非常慢。因为传统的 NFA 接受它找到的第一个匹配,所以它还可能会导致其他(可能更长)匹配未被发现。

POSIX NFA 引擎与传统的 NFA 引擎类似,不同的一点在于:在它们可以确保已找到了可能的最长的匹配之前,它们将继续回溯。因此,POSIX NFA 引擎的速度慢于传统的 NFA 引擎;并且在使用 POSIX NFA 时,您恐怕不会愿意在更改回溯搜索的顺序的情况下来支持较短的匹配搜索,而非较长的匹配搜索。

使用DFA引擎的程序主要有:awk,egrep,flex,lex,MySQL,Procmail等;

使用传统型NFA引擎的程序主要有:GNU Emacs,Java,ergp,less,more,.NET语言,PCRE library,Perl,PHP,Python,Ruby,sed,vi;

使用POSIX NFA引擎的程序主要有:mawk,Mortice Kern Systems’ utilities,GNU Emacs(使用时可以明确指定);

也有使用DFA/NFA混合的引擎:GNU awk,GNU grep/egrep,Tcl。

举例简单说明NFA与DFA工作的区别:

比如有字符串this is yansen’s blog,正则表达式为 /ya(msen|nsen|nsem)/ (不要在乎表达式怎么样,这里只是为了说明引擎间的工作区别)。 NFA工作方式如下,先在字符串中查找 y 然后匹配其后是否为 a ,如果是 a 则继续,查找其后是否为 m 如果不是则匹配其后是否为 n (此时淘汰msen选择支)。然后继续看其后是否依次为 s,e,接着测试是否为 n ,是 n 则匹配成功,不是则测试是否为 m 。为什么是 m ?因为 NFA 工作方式是以正则表达式为标准,反复测试字符串,这样同样一个字符串有可能被反复测试了很多次。

而DFA则不是如此,DFA会从 this 中 t 开始依次查找 y,定位到 y ,已知其后为a,则查看表达式是否有 a ,此处正好有a 。然后字符串a 后为n ,DFA依次测试表达式,此时 msen 不符合要求淘汰。nsen 和 nsem 符合要求,然后DFA依次检查字符串,检测到sen 中的 n 时只有nsen 分支符合,则匹配成功。

由此可以看出来,两种引擎的工作方式完全不同,一个(NFA)以表达式为主导,一个(DFA)以文本为主导。一般而论,DFA引擎则搜索更快一些。但是NFA以表达式为主导,反而更容易操纵,因此一般程序员更偏爱NFA引擎。 两种引擎各有所长,而真正的引用则取决与你的需要以及所使用的语言。

四、实现正则表达式的库:

正则表达式的具体实现通常指具体编程语言或工具所使用的库或模块。例如:

   - **PCRE (Perl Compatible Regular Expressions)**:广泛用于各种语言和工具中,提供了类似Perl语言正则表达式功能的实现。
   - **std::regex**:C++的正则表达式库,可以在C++程序中使用。
   - **re**:这是Python语言中的一个标准库,用于提供正则表达式的支持。
   - **java.util.regex**:Java语言中用于处理正则表达式的类库。
   - **RegExp**:JavaScript中内建的正则表达式支持。

五、正则表达式的语法

正则表达式的语法可以非常复杂,但以下是一些基本的组成元素:

1. **字面量** (Literals):

任何非特殊字符都会匹配它自己。

2. **元字符** (Metacharacters):

在正则表达式中有特殊含义的字符,

如:
   - . 表示任何单个字符(除了换行符)。
   - ^ 表示行的开始。
   - $ 表示行的结束。
   - * 表示前一个字符的0次或多次匹配。
   - + 表示前一个字符的1次或多次匹配。
   - ? 表示前一个字符的0次或1次匹配。
   - {n,m} 表示前一个字符至少n次,不超过m次的匹配。

3. **字符集** (Character classes):

定义一个字符集合,匹配该集合中的任意字符。

   - [abc] 将匹配 "a"、"b" 或 "c"。
   - [^abc] 将匹配 "a"、"b" 和 "c" 之外的任何字符。
   - [a-z] 匹配任何小写字母。
   - [A-Z] 匹配任何大写字母。
   - [0-9] 匹配任何数字。

4. **转义字符** (Escape character): 

\ 被用来转义特殊字符。

   - \t 表示制表符。
   - \n 表示换行符。
   - \\ 表示字面量的反斜杠。
   - \. 表示字面量的点(不再是元字符了)。

5. **锚点** (Anchors):

 \b 和 \B 表示单词的边界和非边界。

   - \b 匹配一个单词边界,即字与空格间的位置。
   - \B 匹配非单词边界。

6. **分组** (Grouping) 和 **捕获** (Capturing):

   - 使用小括号`()`可以将多个字符组成一个单元,这个单元可以用`*+`等元字符来整体匹配。
   - (abc) 表示匹配字面字符串 "abc"。
   - (a|b) 表示匹配 "a" 或 "b"。

7. **非捕获分组** (Non-capturing groups):

使用`(?: ... )`可以进行分组但不捕获匹配的子字符串。

8. **前向和后向断言** (Lookahead and Lookbehind assertions):

   - 前向肯定断言 (?=...) 匹配一个后面跟着特定模式的位置。
   - 前向否定断言 (?!...) 匹配一个后面不跟着特定模式的位置。
   - 后向肯定断言 (?<=...) 匹配一个前面是特定模式的位置。
   - 后向否定断言 (?<!...) 匹配一个前面不是特定模式的位置。

正则表达式在各种编程语言中都有广泛的支持,包括Python、Java、JavaScript、C#、PHP等。在不同的编程语言中,正则表达式的工作方式和性能上可能有所差异,但基本的语法规则是一致的。在实际使用中,由于正则表达式的复杂性,通常推荐先通过文档加深理解,并在在线测试工具上练习,以便熟练掌握其强大的功能。 

六、正则表达式用例

1. **验证电子邮件地址**:

   ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$

   - ^ 匹配输入字符串的开始位置。
   - [a-zA-Z0-9._%+-]+ 匹配前面的字符集合一次或多次(邮件用户名部分)。
   - @ 字面量字符 "@"。
   - [a-zA-Z0-9.-]+ 匹配邮件服务提供商名(域名前部)。
   - \. 字面量点,用来分隔域名的各部分。
   - [a-zA-Z]{2,} 匹配域名后缀(如.com、.org等),至少两个字符。
   - $ 匹配输入字符串的结束位置。

2. **匹配手机号码(以中国为例)**:

   ^1[3-9]\d{9}$

   - ^ 匹配输入字符串的开始位置。
   - 1 字面量数字 "1"。
   - [3-9] 匹配3到9之间的任一数字。(这假定手机号码第二位为3-9之间的数字)
   - \d{9} 匹配任意数字,连续9次。
   - $ 匹配输入字符串的结束位置。

3. **查找HTML标签**:

   <([a-z]+)([^<]+)*(?:>(.*)<\/\1>| *\/>)

   - < 开始的字面小于号。
   - ([a-z]+) 匹配并捕获一次或多次的小写字母(即标签名)。
   - ([^<]+)* 匹配除了小于号之外的任意字符,零次或多次。
   - (?: ... ) 是一个非捕获分组。
   - > 字面量大于号,结束标签的开始部分。
   - (.*) 匹配并捕获任意字符,零次或多次,直到闭标签前。
   - </\1> 中 \1 引用第一个捕获组,匹配相同的标签名。
   - | 表示或操作符,匹配前面或后面的表达式。
   - *\/> 匹配自闭合标签的结尾。

4. **匹配IPv4地址**:

   ^(\d{1,3}\.){3}\d{1,3}$

   - ^ 匹配输入字符串的开始位置。
   - (\d{1,3}\.){3} 单个数字字符重复1到3次,跟着点,这个模式重复3次(对应前三个数字及点)。
   - \d{1,3} 匹配1至3位数的数字字符。
   - $ 匹配输入字符串的结束位置。

5. **简单密码强度校验**:

   ^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$

   - ^ 匹配输入字符串的开始位置。
   - (?=.*[A-Za-z]) 前向断言,确保至少存在一个字母。
   - (?=.*\d) 前向断言,确保至少存在一个数字。
   - [A-Za-z\d]{8,} 匹配8个或更多的字母或数字。
   - $ 匹配输入字符串的结束位置。

每个用例都是根据具体需求制定的,可能会因应用的上下文和要求不同而有所变化。在使用这些正则表达式时,需谨慎考虑边界情况和特定语言实现的细微差别,并应在实际环境中进行充分测试。

相关链接:

正则表达式_百度百科 (baidu.com)

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

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

相关文章

工具系列:PyCaret介绍_编写和训练自定义机器学习模型

文章目录 PyCaret安装PyCaret&#x1f449; 让我们开始吧&#x1f449; 数据集&#x1f449; 数据准备PyCaret中的设置函数&#x1f449; 可用模型&#x1f449; 模型训练与选择&#x1f449; 编写和训练自定义模型&#x1f449; GPLearn模型&#x1f449; NGBoost 模型&#x…

半导体晶圆制造SAP:助力推动新时代科技创新

随着科技的迅猛发展&#xff0c;半导体行业成为了推动各行各业进步的重要力量。而半导体晶圆制造作为半导体产业链的核心环节&#xff0c;其效率和质量的提升对于整个行业的发展起着决定性的作用。在这个高度竞争的行业中&#xff0c;如何提升制造过程的效率、降低成本&#xf…

Bellman_Ford算法总结

知识概览 Bellman_Ford算法适合解决存在负权边的最短路问题&#xff0c;时间复杂度为O(nm)。在存在负权边的最短路问题中&#xff0c;Bellman_Ford算法的效率虽然不如SPFA算法&#xff0c;但是Bellman_Ford算法能解决SPFA算法不能解决的经过不超过k条边的最短路问题。 例题展示…

RPN网络在图像处理中的应用

RPN&#xff08;Region Proposal Network&#xff0c;区域建议网络&#xff09;是深度学习中用于目标检测的关键组件之一&#xff0c;它通常与后续的目标检测网络&#xff08;如Fast R-CNN、Faster R-CNN等&#xff09;结合使用。RPN的主要作用是生成候选目标区域&#xff0c;从…

OpenGL 绘制Mesh数据(Qt)

文章目录 一、简介二、实现代码三、实现效果一、简介 Mesh数据的结构主要就是点与三角面片,因此本质上仍然是对三角面片进行绘制。这里我们借助VCG这个库实现对Mesh数据的读取,这个库相对简单轻巧,很方便使用。 二、实现代码 由于修改的部分很多,我们逐一进行解释一下: --…

快速入门学习定时任务框架-xxljob

定时任务框架-xxljob 简介 主要用于分布式任务调度&#xff0c;可以将任务调度和执行分布在多个节点上。它提供了一个集中式的管理平台&#xff0c;支持动态添加、修改、删除任务&#xff0c;以及任务的分片执行&#xff0c;确保任务在分布式环境中的高可用性的一个框架 spr…

【刷题篇】动态规划(八)

文章目录 1、最长定差子序列2、 最长的斐波那契子序列的长度3、最长等差数列4、等差数列划分 II - 子序列5、回文子串6、最长回文子串 1、最长定差子序列 给你一个整数数组 arr 和一个整数 difference&#xff0c;请你找出并返回 arr 中最长等差子序列的长度&#xff0c;该子序…

Python爬虫中文乱码处理实例代码解析

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python爬虫中文乱码处理实例代码解析。全文2800字&#xff0c;阅读大约8分钟 在进行网络数据抓取时&#xff0c;常常会遇到中文乱码的问题&#xff0c;这可能导致数据无法正…

编程规范:长函数的思考

在工作&#xff0c;我们应该都不想看到非常的长函数。对于一个运行5年左右的项目&#xff0c;极有可能出现这种情况。由于长函数的长、if/else嵌套&#xff0c;导致代码的可读性非常差&#xff0c;这对于项目的维护和开发带来了极大的困难。所以我们应该避免写长函数&#xff0…

基于稀疏表示的小波变换多光谱图像融合算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 小波变换融合 PCA融合 基于稀疏表示的小波变换多光谱图像融合算法 性能指标对比 2.算法运行软件版本 matlab2022a 3.部分核心程序 ...........…

Redis相关的那些事(一)

背景 目前工作所负责的工作主要是投放业务&#xff0c;属于读高并发场景&#xff0c;记录一下之前碰到的redis相关的问题。 热点大值Key&缓存击穿问题 问题表现 在某次流量峰值过程中&#xff0c;redis的CPU突然飙升&#xff0c;从监控看起来就是CPU飙升到一定程度&…

微信小程序(uniapp)api讲解

Uniapp是一个基于Vue.js的跨平台开发框架&#xff0c;可以同时开发微信小程序、H5、App等多个平台的应用。下面是Uniapp常用的API讲解&#xff1a; Vue.js的API Uniapp采用了Vue.js框架&#xff0c;因此可以直接使用Vue.js的API。例如&#xff1a;v-show、v-if、v-for、comput…

基于HC-SR04传感器的避障机器人设计与实现

本文介绍了如何设计和实现一个基于HC-SR04超声波传感器的避障机器人。我们将详细讨论硬件和电路连接&#xff0c;并提供完整的Arduino代码。该机器人可以利用超声波传感器检测周围的障碍物&#xff0c;并采取相应的动作进行避障&#xff0c;实现自主导航。 引言&#xff1a; 避…

微服务架构<2>

在电商项目中&#xff0c;我们针对一些核心业务&#xff0c;比较复杂的业务需要做一些设计以及优化的过程首先我们针对于订单的模块拆分了2个子模块1.order-curr实时下单业务 2.order-his 做一些历史的订单归档我们的订单业务 >商品添加至购物车 >购物车结算--> 订单…

sklearn 逻辑回归Demo

逻辑回归案例 假设表示 基于上述情况&#xff0c;要使分类器的输出在[0,1]之间&#xff0c;可以采用假设表示的方法。 设 h θ ( x ) g ( θ T x ) h_θ (x)g(θ^T x) hθ​(x)g(θTx)&#xff0c; 其中 g ( z ) 1 ( 1 e − z ) g(z)\frac{1}{(1e^{−z} )} g(z)(1e−z)1​…

Go语言中的`sync`包同步原语

通过sync包掌握Go语言的并发 并发是现代软件开发的基本方面&#xff0c;而Go&#xff08;也称为Golang&#xff09;为并发编程提供了一套强大的工具。在Go中用于管理并发的基本包之一是sync包。在本文中&#xff0c;我们将概述sync包&#xff0c;并深入探讨其最关键的同步原语…

第二十一章博客

计算机应用实现了多台计算机间的互联&#xff0c;使得它们彼此之间能够进行数据交流。网络应用程序就是在已连接的不同计算机上运行的程序&#xff0c;这些程序借助于网络协议&#xff0c;相互之间可以交换数据。编写网络应用程序前&#xff0c;首先必须明确所要使用的网络协议…

1 手写第一个Win32窗口程序

1 基础概念 什么是窗口&#xff1f; 答&#xff1a;窗口就是屏幕上的一片区域&#xff0c;接受用户的输入&#xff0c;显示程序的输出。可以包含标题栏、菜单栏、工具栏以及控件等。什么是句柄&#xff1f; 答&#xff1a; 作为一种管理和操作系统资源的机制&#xff0c;提供了…

【AI提示词故事】雪的诗意:静谧与活力的奇妙交织

雪的诗意&#xff1a;沉浸在雪景的浪漫氛围中 冬日的清晨&#xff0c;窗外的世界被一层洁白的雪覆盖着&#xff0c;仿佛是大自然为我们准备的一幅美丽画卷。 我走出房门&#xff0c;踏上雪地&#xff0c; 那柔软的雪粒在脚下发出轻柔的咯吱声&#xff0c;仿佛是在诉说着冬日的…

SQL进阶:子查询

一般情况下,我们都是直接对表进行查询,但有时候,想要的数据可能通过一次select 获取不到,需要嵌套select,这样就形成了子查询。 子查询可以位于查询语句的任意位置,主要的注意点在于用于不同的位置,和不同的关键字一起使用时,需要注意返回的列的数量和行的数量。 位于…