博客主页:https://tomcat.blog.csdn.net
博主昵称:农民工老王
主要领域:Java、Linux、K8S
期待大家的关注💖点赞👍收藏⭐留言💬
目录
文章说明
正则表达是应用广泛的工具。不论您是否从事编程相关的工作,都应学习掌握。特别是如公务员、教师、大学生、公司文员等需要经常进行文字处理的人群,正则表达式也一定能提高您的工作效率。
本文是我学习正则表达式的笔记,主要是对网络资料的汇总整理和练习。同时也是面向文字工作者的一篇科普文章。
需要注意的是,正则表达式的具体写法在不同的语言中略有不同,本文采用的语言风格是PCRE2。在线练习环境推荐 https://regex101.com/,该网站的默认语言风格就是PCRE2;离线环境推荐Sublime Text,这是一个免费的文本处理软件,Windows系统和Mac系统都很容易下载到,这个软件会自动适配正则表达式语言风格。
如果您有一定的编程基础,请结合您使用的编程语言对正则表示具体的写法进行学习。
本文现在只是第一版,后续还会继续完善。既会补充知识点,也有在Java 代码或Shell脚本中的应用,还有在Sublime Text中的使用示例。
本文在概念的分类方面有按照自己的理解进行调整,文中的示例和配图也全是自己的原创表达。如果您发现文中有错误,欢迎在评论区指正。码字不易,欢迎关注,点赞,评论。如果转载,请注明出处——农民工老王的CSDN博客。
正则表达式概述
什么是正则表达式
正则表达式,简称正则(regex),是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
简单地说:正则表达式就是描述文本内容组成规律的字符串
正则表达式用途
在编程语言中,正则常常用来简化文本处理的逻辑。它的应用极其广泛。我们可以利用它来校验数据的有效性,比如用户输入的手机号是不是符合规则;也可以从文本中提取想要的内容,比如从网页中抽取数据;还可以用来做文本内容替换,从而得到我们想要的内容。
如下图,就展示了我们在日常生活常见的一个文本处理案例:
在某个商家公布中奖名单时,既要方便阅读者能核实到除了姓名之外的手机号码(为了避免重名),又要保护被公示者的个人隐私,这就需要将手机号码中间四位换成“ * ”。类似的处理需求还有很多,比如公务员考试公布录用名单,需要在 人名 + 身份证 的字符串中,对身份证中间几位进行处理。
上图的这个文字处理,如果要通过Word或者Excel完成,还是比较复杂,大部分人只有一个个电话号码地操作。不仅繁琐浪费时间,还容易出错。
但是如果用正则表达式就很方便。如下图所示,在Sublime Text中按Ctrl + H ,窗口下方弹出替换工具,然后在Find 和 Replace中填入相应的正则表达式,然后点击右下角的 Replace 按钮,就可实现全部的替换。
元字符
元字符就是指那些在正则表达式中具有特殊意义的专用字符,元字符是构成正则表达式的基本元件。正则就是由一系列的元字符组成的。因为元字符很基础,又比较多,建议分类记忆。元字符可以分为表义单字符,范围,量词,断言。
表义单字符
我们来看下表示特殊单个字符的元字符,比如英文的点(.)表示换行以外的任意单个字符,\d 表示任意单个数字,\w 表示任意单个数字或字母或下划线,\s 表示任意单个空白符。另外,还有与之对应的三个 \D、\W 和 \S,分别表示着和原来相反的意思。
符号 | 含义 | 注释 |
---|---|---|
. | 除换行外的任意字符 | - |
\d | 任意数字 | 取自单词digit |
\w | 任意数字字母下划线 | 取自单词word; Python中包含汉字 |
\s | 任意空白符 | 取自单词space; \r回车 \n换行 \t制表符 \v垂直制表符 |
量词
刚刚说到的表义单字符都只能匹配单个字符,比如\d 只能匹配一个数字。但更多时候,我们需要匹配单个字符,或者某个部分“重复 N 次”“至少出现一次”“最多出现三次”等等这样的字符,这个时候该怎么办呢?这就需要用到表示量词的元字符了。在正则中,英文的星号(*)代表出现 0 到多次,加号(+)代表 1 到多次,问号(?)代表 0 到 1 次,{m,n}代表 m 到 n 次(闭区间)。
符号 | 含义 |
---|---|
* | 0到n次 |
+ | 1到n次 |
? | 0到1次 |
{m} | m次 |
{m,} | 至少m次 |
{m,n} | m到n次 |
范围
学习了量词,我们就可以用 \d{11} 去匹配所有手机号,但同时也要明白,这个范围比较大,有一些不是手机号的数字也会被匹配上,比如 11 个 0,那么我们就需要在一个特殊的范围里找符合要求的数字。这又要如何实现呢?在正则表达式中,表示范围的元字符可以轻松帮我们搞定这样的问题。在正则表达式中,表示范围的符号有三个分类,如下表所示。
符号 | 含义 | 注释 |
---|---|---|
| | 或 | 如 ArcGIS|Esri 表示 ArcGIS或Esri |
[…] | 多选一 | 如 [abc] 表示a,b,c中的任何一个 |
[^…] | 取反 | 不能是括号中除了^的任意字符 |
另外,中括号中,我们还可以用中划线表示范围,比如 [a-z] 可以表示所有小写字母。如果中括号第一个是脱字符(^),那么就表示非,表达的是不能是里面的任何单个元素。
断言
断言是指对匹配到的文本位置有要求。在有些情况下,我们对要匹配的文本的位置也有一定的要求。为了解决这个问题,正则中提供了一些结构,只用于匹配位置,而不是文本内容本身,这种结构就是断言。常见的断言有三种:单词边界、行的开始或结束以及环视。
符号 | 名称 | 含义 | 实例 |
---|---|---|---|
\b | 单词边界 | – | \btom\b只匹配tom,不匹配tomcat |
^ | 开始 | – | – |
$ | 结束 | – | – |
?<=Y | 肯定逆序环视 | 左侧是Y | (?<=\d)th左边是数字的th,能匹配9th |
?<!Y | 否定逆序环视 | 左边不是Y | (?<!\d)th左边不是数字的th,能匹配health |
?=Y | 肯定逆序环视 | 右边是Y | six(?=\d)右边是数字的six,能匹配six6 |
?!Y | 否定逆序环视 | 右边不是Y | hi(?!\d)右边不是数字的hi,能匹配high |
元字符的转义
在使用正则表达式的时候,有时候会遇到具有特殊意义的字符(如匹配元字符本身),或者是无法直接键盘录入的字符(如回车符)。这时就需要用转义字符,转义通过“\”实现。比如查找“\d”,那其匹配的正则表达式应为“\\d”。
分组与引用
括号在正则中可以用于分组,被括号括起来的部分“子表达式”会被保存成一个子组。那分组和编号的规则是怎样的呢?其实很简单,用一句话来说就是,第几个括号就是第几个分组。这么说可能不好理解,我们来举一个例子看一下。
我们可以写出如图所示的正则,将日期和时间都括号括起来。这个正则中一共有两个分组,日期是第 1 个,时间是第 2 个。
有些情况会比较复杂,比如在括号嵌套的情况里,我们要看某个括号里面的内容是第几个分组怎么办?不要担心,其实方法很简单,我们只需要数左括号(开括号)是第几个,就可以确定是第几个子组。
分组后是为了能引用,可以用$+分组编号进行引用。
分组可以简化查找和替换的效率。比如下图。
如上图这样的替换,可应用于很多文字工作处理场景,在查找和替换方面,定能帮助您实现比word里的普通文本替换更高效的操作。
匹配模式
所谓匹配模式,指的是正则中一些改变元字符匹配行为的方式,比如匹配时不区分英文字母大小写。常见的匹配模式有 4 种,分别是不区分大小写模式、点号通配模式、多行模式和注释模式。
模式修饰符是通过 (? 模式标识) 的方式来表示的。 我们只需要把模式修饰符放在对应的正则前,就可以使用指定的模式了。
不区分大小写模式
在不区分大小写模式中,由于不分大小写的英文是 Case-Insensitive,那么对应的模式标识就是 I 的小写字母 i,如图所示,不区分大小写的Linux就可以写成 (?i)Linux。值得注意的是,图中的 (?i)Linux,外加了括号,这是表示不区分大小写的范围为括号内,如果不加括号,那么则是(?i)后所有内容都不区分大小写。
点号通配模式
让英文的点(.)可以匹配上包括换行的任何字符。这个模式就是点号通配模式。
单行模式对应的修饰符是 (?s) 。
多行模式
通常情况下,^匹配整个字符串的开头,$ 匹配整个字符串的结尾。多行匹配模式改变的就是 ^ 和 $ 的匹配行为。多行模式的作用在于,使 ^ 和 $ 能匹配上每行的开头或结尾,我们可以使用模式修饰符号 (?m) 来指定这个模式。
这个模式有什么用呢?在处理日志时,如果日志以时间开头,有一些日志打印了堆栈信息,占用了多行,我们就可以使用多行匹配模式,在日志中匹配到以时间开头的每一行日志。
紧接着下面的两张图中,第一张图演示了未使用多行匹配模式的效果,第二张图演示了使用多行匹配的效果。
注释模式
在实际工作中,正则可能会很复杂,这就导致编写、阅读和维护正则都会很困难。我们在写代码的时候,通常会在一些关键的地方加上注释,让代码更易于理解。很多语言也支持在正则中添加注释,让正则更容易阅读和维护,这就是正则的注释模式。正则中注释模式是使用 (?#comment) 来表示。
量词与贪婪
如果正则表达式中有量词,那么就涉及到量词的贪婪与否。本节内容为选学内容,非编程从业者不太需要了解。
本节就以如:正则表达式 a{1,5}ab,匹配文本aaab 为案例 ,解释分析量词在贪婪方面的三种匹配方式:
贪婪匹配
默认就是贪婪模式,在满足要求的情况下,先尽可能长地去匹配。失败后会回溯。
第一轮,正则表达式中的“a{1,5}”,尽量取长,匹配到了“aaa”,但正则表达式后面的“a“” ,匹配不了文本剩下的“b”。
这一轮没有匹配成功,就触发了回溯,如何回溯呢?第一次匹配了3个“a”没有成功,那第二轮就尝试匹配2个"a。
第二轮,正则表达式中的“a{1,5}”,尝试匹配两个“a”,匹配到了“aa”,然后正则表达式中的“a”匹配到字符串中的“a”,正则表达式中的“b”匹配到字符串中的“b”。匹配成功,且到达字符串末尾,因而匹配结束。
如图所示:
非贪婪匹配
在量词元字符后加英文问号,满足要求的情况下,尽可能地按最短去匹配,有回溯。
和贪婪匹配的差别是量词是从最小值开始一轮轮匹配。如图所示:
独占模式
在量词原字符后加英文加号,满足要求的情况下,尽可能地按最长的去匹配,无回溯。
和贪婪匹配相比,是独占模式不回溯。也就是说第一轮匹配失败后,就结束匹配。其流程相当于只有贪婪模式的第一轮,因为在独占模式下正则表达式 a{1,5}ab 不能匹配的文本aaab 中的任何字符。
需要注意的是 Python 和 Go 的标准库目前都不支持独占模式。需要自行引入类库。因为独占模式不进行回溯,因此在一些场景下,可以提高匹配的效率,具体能不能用,需要看独占模式能不能满足需求。
常见的正则表达式
匹配18位身份证号:(\d{6})(\d{4})(\d{2})(\d{2})(\d{3})([0-9]|X)
匹配E-mail:(?m)^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
匹配大陆电话号码/手机号码:(1\d{10})|(\d{4}-?\d{7})|(\d{3}-?\d{8})
相关网站/软件
在文末推荐几个练习正则的网站或者软件,大家按需自取吧。
- 正则在线测验平台:https://regex101.com/
- 正则可视化在线工具1:http://regexper.com/
- 正则可视化在线工具2:https://jex.im/regulex/
- 正则国内测验工具1:https://tool.oschina.net/regex/
- 正则国内测验工具2:https://c.runoob.com/front-end/854
- Windows系统 正则软件:RegexBuddy
- Mac系统 正则软件:Expressions
结语
本文只是一个入门的学习笔记,如果要真正掌握正则,还需要您进行更多的深入学习,并在日常工作中多多练习。
如需转载,请注明本文的出处:农民工老王的CSDN博客https://blog.csdn.net/monarch91 。