【文本处理】正则表达式

一、简介

正则表达式,又称规则表达式,(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)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

在Redis客户端设置连接密码 并演示密码登录

我们先连接到Redis服务 然后 我们要输入 CONFIG SET requirepass “新密码” 例如 CONFIG SET requirepass "A15167"这样 密码就被设置成立 A15167 我们 输入 AUTH 密码 例如 AUTH A15167这里 返回OK说明成功了 然后 我们退出在登录就真的需要 redis-cli -h IP地…

嵌入式开发——PWM高级定时器

学习目标 加强掌握PWM开发流程理解定时器与通道的关系掌握多通道配置策略掌握互补PWM配置策略掌握定时器查询方式掌握代码抽取优化策略掌握PWM调试方式学习内容 需求 点亮8个灯,采用pwm的方式。 定时器 通道 <

vue3 新项目 - 搭建路由router

创建router/index 文件 main.ts 安装 router 然后 在 app下面 去 设置 路由出口

【贪心】买卖股票的最佳时机含手续费

/** 贪心&#xff1a;每次选取更低的价格买入&#xff0c;遇到高于买入的价格就出售(此时不一定是最大收益)。* 使用buy表示买入股票的价格和手续费的和。遍历数组&#xff0c;如果后面的股票价格加上手续费* 小于buy&#xff0c;说明有更低的买入价格更新buy。如…

深度神经网络下的风格迁移模型(C#)

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 这个是C#版本的&#xff0c;这里就只放出代码。VB.Net版本请参看 深度神经网络下的风格迁移模型-CSDN博客 斯坦福大学李飞飞团队的…

智能优化算法应用:基于天鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于天鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于天鹰算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.天鹰算法4.实验参数设定5.算法结果6.参考文献7.MA…

Unity PlayerPrefs存储数据在Windows环境中本地存储的位置

Unity PlayerPrefs存储数据在Windows环境中本地存储的位置 一、编辑器模式下的PlayerPrefs存储位置1.Win r 输入regedit进入注册表界面2. HKEY_CURRENT_USER/Software/Unity3.CompanyName和ProjectName可以在Unity->Edit->Project Settings->Player中查看和设置 二、…

Vue3数据交互axios

我是南城余&#xff01;阿里云开发者平台专家博士证书获得者&#xff01; 欢迎关注我的博客&#xff01;一同成长&#xff01; 一名从事运维开发的worker&#xff0c;记录分享学习。 专注于AI&#xff0c;运维开发&#xff0c;windows Linux 系统领域的分享&#xff01; 本…

Git系统有哪些优势

在现在的这个软件开发领域&#xff0c;版本控制是一项非常重要的工作。Git作为比较流行的分布式版本控制系统&#xff0c;他有着独特的优势成为了很多开发者们的首选。那Git系统都有哪些优势呢&#xff0c;下面我以自己的理解简单的介绍一下。 分布式版本控制的优势 Git用的是…

Java多线程、线程池及线程同步(synchronized关键字、悲观锁、乐观锁)

1.进程与线程定义 进程包含线程&#xff0c;如一个百度网盘进程&#xff0c;该进程的线程可以有上传&#xff0c;下载。 2.创建线程的三种方式 方式1-继承Thread类 方式2-实现Runnabled接口 1.常规写法 2.匿名内部类写法 方式3-实现Callable接口 示例代码&#xff1a; f1.get…

nginx 利用 error_page 实现自定义 404 跳转

文章目录 [toc]指定错误代码的 url 路径使用 response 来更改状态码使用 URL 重定向开始搞事情创建一个 404 文件配置 conf 文件通过 CURL 命令验证 error_page 以下内容&#xff0c;摘抄翻译自官网 语法格式 - error_page code ... [[response]] uri;上下文 - http, server, l…

【数据结构入门精讲 | 第十篇】考研408排序算法专项练习(二)

在上文中我们进行了排序算法的判断题、选择题的专项练习&#xff0c;在这一篇中我们将进行排序算法中编程题的练习。 目录 编程题R7-1 字符串的冒泡排序R7-1 抢红包R7-1 PAT排名汇总R7-2 统计工龄R7-1 插入排序还是堆排序R7-2 龙龙送外卖R7-3 家谱处理 编程题 R7-1 字符串的冒…

SpringSecurity6 | 失败后的跳转

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: Java从入门到精通 ✨特色专栏: MySQL学习 🥭本文内容: SpringSecurity6 | 失败后的跳转 📚个人知识库: Leo知识库,欢迎大家访问 学习…

rk3588 之启动

目录 uboot版本配置修改编译 linux版本配置修改编译 启动sd卡启动制作spi 烧录 参考 uboot 版本 v2024.01-rc2 https://github.com/u-boot/u-boot https://github.com/rockchip-linux/rkbin 配置修改 使用这两个配置即可&#xff1a; orangepi-5-plus-rk3588_defconfig r…

高级人工智能之群体智能:蚁群算法

群体智能 鸟群&#xff1a; 鱼群&#xff1a; 1.基本介绍 蚁群算法&#xff08;Ant Colony Optimization, ACO&#xff09;是一种模拟自然界蚂蚁觅食行为的优化算法。它通常用于解决路径优化问题&#xff0c;如旅行商问题&#xff08;TSP&#xff09;。 蚁群算法的基本步骤…

【C->Cpp】深度解析#由C迈向Cpp(2)

目录 &#xff08;一&#xff09;缺省参数 全缺省参数 半缺省参数 缺省参数只能在函数的声明中出现&#xff1a; 小结&#xff1a; &#xff08;二&#xff09;函数重载 函数重载的定义 三种重载 在上一篇中&#xff0c;我们从第一个Cpp程序为切入&#xff0c;讲解了Cpp的…

Topaz Video AI 视频修复工具(内附安装压缩包win+Mac)

目录 一、Topaz Video AI 简介 二、Topaz Video AI 安装下载 三、Topaz Video AI 使用 最近玩上了pika1.0和runway的图片转视频&#xff0c;发现生成出来的视频都是有点糊的&#xff0c;然后就找到这款AI修复视频工具 Topaz Video AI。 一、Topaz Video AI 简介 Topaz Video…

Openai的openai新版本调用方式

最近大家有没有发现Openai的openai已经更新到1.6.1了,而且API的调用方式发生了巨大的变化,下面来看看openai新的调用方式吧。 欢迎关注公众号 module ‘openai’ has no attribute ChatCompletion. 提示openai的版本过低。(pip install -U openai) 1. Chat API from openai…

【MySQL学习笔记008】多表查询

1、多表关系 概述&#xff1a;项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系&#xff0c;基本上可分为三种&a…

freeRTOS实时操作系统学习笔记

温馨提示&#xff1a;点击图片查看大图更清晰 —————————————————————————————↑↑↑上方资源下载后可获取xmind原文件。 1、freeRTOS移植和配置脑图 2、内核源码学习