前言
阅读时间:10-15 分钟
推荐书籍:《正则表达式必知必会》
推荐 debug 网址:regex101.com/
正则表达式已经出现过许多年了,相信大家在工作中或多或少的接触过。但是有些人比如我,在初次阅读和理解上会有一些困难,即使查阅一些相关的语法,也很难融会贯通,举一反三,只想着通过谷歌和百度快速找到当前问题的解决方案。然而问题总比办法多,有些特定场景的问题只能自食其力,因此在这里总结了正则表达式一些常用的知识点,希望大家再次遇到正则相关的问题时能够举重若轻,从容过关。
正则表达式说简单挺简单,说难却不难,只是在有些场景中涉及到的正则表达式有些复杂,需要大家耐心一些,抽丝剥茧,对每一个字符各个击破。下图举例一个简单的正则表达式 hello word 作为我们学习的起点,它将匹配文本中的 hello word 字符串。
正则表达式的作用
开宗明义,我们先来理解正则表达式是什么,直接下定义:
正则表达式是人们为了解决搜索和替换问题而发明的一种工具。
匹配特定字符串的问题,相信大家用字符串操作也能快速解决,但是有一些复杂场景下的问题,可就没那么容易了,例如搜索文本中的电子邮件(eg: mock@foxmail.com),想用字符串操作解决的话,预期要在循环体里用一系列的 if 语句,难以维护且不够优雅,但是使用正则表达式的话,仅仅一行即可(eg: \w+@(\w+\.)+[a-zA-Z]+)。
值得一提的是,同一个问题的解决往往可以有多个正则表达式,越复杂的正则表达式性能开销越大,因此需要结合自己的数据格式思考合适的正则表达式。
好了,废话已多说,让我们开始正则表达式学习之旅吧。
工具说明
文中的附图均截图自 regex101.com/ ,正则表达式输入框末尾的 gm 表示全局匹配和多行匹配。
图中左下蓝色代表搜索到的字符或字符串,右上绿色说明了匹配上的数量
1、下图只匹配上一个字符串,该字符串是 hello world
2、下图中匹配上了四个字符串,分别是四个 ab
匹配单个字符
下面我们列举了一些由常见的字符组成的字符串,我们来学习如何利用正则表达式匹配我们想要的单个字符。
abcABC123/\.*?
1、前文例证已指出,匹配一个特定的字符的正则表达式就是该字符,比如我们想匹配 a 字符:
2、那么如何匹配 a b c 三个中的任意一个呢,此时我们可以借助正则表达式的元字符[],中括号里面的字符是或的关系:
3、中括号虽然解决了问题,但是如果我们想匹配 26 个字母,则需要在中括号里把字母都写一边,非常冗长,正则表达式为此有一个简化的写法,在首尾字符中间加一个 -,即可表示范围:
4、我们还可以在中括号中加一个 ^ ,来表示取反的意思,这样我们就可以匹配除 a b c 以外的其他字符:
5、那么如何匹配上文本示例中的全部字符呢,我们当然可以在中括号中写上全部的范围,但是十分冗长,因此正则表达式定义了一个元字符.可以匹配除换行符以外的任意字符:
6、有敏锐的同学可能就要问了,这样的话如何匹配 . 本身呢,是的,就是大家耳熟能详的转义啦,正则表达式中,元字符匹配本身需要在前面加一个转义字符 \ :
数字类型和字母类型一样,都可以用同样的方式去匹配,利用中括号我们已经可以匹配上文本中所有的单个字符,但是我们也可以发现,中括号在匹配交大的范围时还是有些不方便,因此正则表达式还定义了一些特殊的元字符来简单的表示匹配的范围,如下表所示:
| 范围 | 说明 | 表达式 |
|---|---|---|
| 任何一个数字字符 | [0-9] | \d |
| 任何一个非数字字符 | [^0-9] | \D |
| 任何一个数字字母或下划线字符 | [a-zA-Z0-9_] | \w |
| 任何一个非数字字母或下划线字符 | [^a-zA-Z0-9_] | \W |
| 任何一个空白字符 | [\f\n\r\t\v] | \s |
| 任何一个非空白字符 | [^\f\n\r\t\v] | \S |
匹配多个字符
通过上述内容的学习,我们已经可以成功匹配文本中的单个字符,那么下面我们来开始学习匹配多个字符,我们列举一些常用的字符串进行学习:
abcabc123456\\\..
1、同样的,匹配一个特定的字符串的正则表达式就是该字符串,比如匹配 abc 。
2、如果我们想匹配由三个字符组成的字符串,三个字符可以是 a b c 任意中的任意一个,通过之前的学习我们知道可以利用中括号:
3、有细心的小伙伴就要问了,这里写了三个一摸一样的中括号,工作中我们应该避免重复,因此,正则表达式定义了元字符大括号 {} 来表示前一字符匹配的数量:
4、有时候我们不明确要匹配的数量,我们还可以在大括号中输入一个范围:
和中括号一样,正则表达式也有一些特殊的元字符来表示匹配的数量,从而简化大括号的书写,如下表所示:
| 范围 | 说明 | 表达式 |
|---|---|---|
| 匹配一个或多个 | {1,} | + |
| 匹配零个或多个 | {0,} | * |
| 匹配零个或一个 | {0,1} | ? |
匹配分组
现在我们已经学会大部分场景下的正则表达式了,但是有时候用起来不那么方便,比如我们希望匹配一个 IP 地址如下:
127.0.0.1
我们可以用已经学习过的正则知识写出这个表达式:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
简单分析一下,\d{1,3} 匹配一到三个数字,\. 匹配一个字符 . 因为是元字符所以需要转义,IP 地址有四个部分,前三个部分导致我们将 \d{1,3}\. 我们连续写了三次,还是出现了重复,但是之前的学习中大括号只用于表示前一个字符的匹配数量,\d{1,3}\. 后直接加大括号只能表示 \. 的数量,此时我们可以利用分组解决这个问题。
正则表达式中可以用小括号 () 来分组,分组之后就可以用大括号来表示数量啦,我们可以改写如下:(\d{1,3}\.){3}\d{1,3}
学到这里,文章开头说的电子邮件的正则表达式是不是就可以轻松看懂了,我们这里简单解释一下, \w+ 表示一个或多个数字字母下划线,匹配文本中的 mock ,然后再接一个固定字符 @ ,然后 (\w+\.)+ 表示多个分组,每一组包含一个或多个数字字母下划线再加一个点,匹配文本中的 foxmail. , 最后 [a-zA-Z]+ 表示一个或多个字母,匹配文本中的 com 。
前后查找
好了,我们一鼓作气再学习本文最后一个知识点吧,我们现在基本可以匹配所有情况下的文本啦,但是有时候写出正则表达式除了匹配我们想要的文本外,还是匹配到一些我们不想要的文本,比如以下文本中我们用表达式 [0-9.]+ 希望匹配商品的价格:
但是发现一些非价格的数字也被匹配上了,这时候向后查找的作用就出来了,我们可以用表达式 (?<=\$)[0-9.]+ 表示只匹配 $ 字符后面的数字。
同样的,除了向后查找以外,正则表达式也支持向前查找,如下表所示:
| 说明 | 表达式 |
|---|---|
| 肯定的向前查找 | (?=) |
| 否定的向前查找 | (?!) |
| 肯定的向后查找 | (?<=) |
| 否定的向后查找 | (?<!) |
总结
本文带大家从单个字符多字符串的正则表示式的理解过程,同时结合实际场景说明了分组和前后查找的用处,相信学会这些大家已经可以从容的面对工作中的正则表达式啦。
值得一提的是,为了讲述思维的连贯性,本文并没有详尽的枚举正则表达式的所有规则和元字符,有了文中的重点知识铺垫,剩下的一些知识点,大家主动了解一下,一定可以快速掌握。
最后祝大家码上暴富。