前言
正则表达式(Regular Expression)是一种既简单,又使用非常广泛的一种技术,我在题目中称其为"必会技术",这并不夸张,无论是从事开发工作还是做一些文案类工作,甚至日常使用电脑搜索一个文件,都会接触到正则表达式。当然,在很多场景下不使用正则表达式也可以完成同样的工作,但是相对要麻烦很多。正则表达式,不熟悉的人第一眼看上去很容易把它认为是一种数学或者其他理工科中的一种表达公式,其实它和公式并没有太大关系。正则表达式是一种文本匹配模式,它能够使用一个或多个简单的字符,去描述匹配一些复杂句法的规则,例如网页、身份证号、出生年月日、家庭住址等。正是因为它的简单且不失强大的特性,它在很多地方都有着应用,一下举几个例子,
- everything文件搜索
- Python、JS、PHP相关开发
- pycharm、sublime等编辑器及IDE
- 爬虫
- ……
也许说到这里还是有一些同学感觉云里雾里,下面就以一个简单的例子来说明一下。假如,给你一个长篇的文章或者上万字的网页,你想从其中匹配出里面的信息,例如身份证号,你会怎么办?当然,这有很多种方法,甚至可以采用最笨的遍历方法去寻找,但是这并不是一个聪明的选择,我们这时就可以使用一个简短的正则表达式来进行匹配,假设下面是要匹配的文本,在陆游的《钗头凤·红酥手》和唐婉的《钗头凤·世情薄》之间插入一个18位、末位为X的假身份证号,
红酥手,黄縢酒,满城春色宫墙柳。东风恶,欢情薄。一怀愁绪,几年离索。错、错、错。
春如旧,人空瘦,泪痕红浥鲛绡透。桃花落,闲池阁。山盟虽在,锦书难托。莫、莫、莫!
23453419901011908X
世情薄,人情恶,雨送黄昏花易落。晓风干,泪痕残,欲笺心事,独语斜阑。难,难,难!
人成各,今非昨,病魂常似秋千索。角声寒,夜阑珊,怕人寻问,咽泪装欢。瞒,瞒,瞒!
对于文本中身份证号的匹配就可以使用下面这段正则表达式,
(\d{18})|([0-9]{17}(X|x$))
看一下匹配结果,
在解释上述正则表达式含义之前,我们首先想一下身份证号有哪些特点,
- 身份证号长度为15位或者18位
- 末位为数字或者大写X或者小写x
以上述文本为例,身份证号长度为18、末位为X,下面来看一下上述正则表达式,
正则表达式中竖线 | 表示“或”的意思,可以在多个片段中进行选择,所以上述正则表达式可以分为2部分,
- (\d{18})
- ([0-9]{17}(X|x$))
其中(\d{18})中\d匹配任意数字,后面大括号是对前面子表达式的限定符,括号里为整数,表示的含义是匹配前面子表达式的次数,因此这个表达式的含义就是匹配\d18次,换句话说就是匹配数字18次,而有些身份证号就是18位的纯数字,因此这个表达式可以匹配18位纯数字的身份证号。
然后再看([0-9]{17}(X|x$)),这里面[0-9]和\d的含义是相同的,匹配0-9之间的数字,后面的17的含义是匹配前面数字17次,然后X|x$的含义是以X或x结尾,$是匹配结尾的含义,因此这个表达式的含义就是匹配另外一种身份证号,前面为数字末位为X或x的身份证号。
到这里,就应该了解了上述正则表达式的含义,匹配两种身份号,一种为纯数字,一种末位为X或x。
当然,正则表达式的价值远不止于匹配身份证号这么简单,它可以用于一些自然语言处理的数据粗提取,可以用于网页爬虫去匹配一些网页内容、网页链接,同时还可以用于linux命令行的字符、文件匹配。
读到这里应该就明白,正则表达式就是一些具有特殊含义字符以不同方式组合在一起形成的文本匹配模式,因此,学习正则表达式的关键点也就很明确了,需要了解不同字符的含义,下面就来详细介绍一下。
字符分类
我把正则表达式的字符分为如下三类分别进行讲解,
- 元字符
- 限定字符
- 特殊字符
元字符
开头和结尾
字符 | 描述 |
^ | 匹配字符字符串的开始位置 |
$ | 匹配字符字符串的结尾位置 |
假如,待匹配的文本如下,
hello
elloh
llohe
正则表达式及匹配结果为,
^h.+ # 正则表达式
hello # 匹配结果
.+e$ # 匹配结果
llohe # 匹配结果
匹配次数相关字符
字符 | 描述 |
* | 匹配前面子表达式0次或多次 |
+ | 匹配前面子表达式1次或多次 |
? | 匹配前面子表达式0次或1次 |
假设待匹配文本为,
helloooo
正则表达式及匹配结果为,
[0-9]{4} # 正则表达式 1919 # 匹配结果 1903 8038 4083
限定字符
前面讲到的可以用一些元字符来匹配“次数”相关的字符,但是这些都是模糊的匹配,零次或多次、零次或1次、1次或多次,不够精确。除了这些元字符外还可以通过限定符来匹配准确数量的字符,限定符是以大括号进行标识,
字符 | 描述 |
{n} | 匹配前面子表达式n次 |
{n,} | 匹配前面子表达式至少n次 |
{n,m} | 匹配前面子表达式至少n次,最多m次 |
假设待匹配为,
1919190380384083
正则表达式及匹配结果为,
[0-9]{4} # 正则表达式
1919 # 匹配结果
1903
8038
4083
特殊字符
有一些特殊字符在不同的场景下含义不尽相同,例如?紧跟一个字表达式,含义是匹配0次或者1次,如果跟随其他次数限定相关的字符,它就变成了非贪婪的,也就是说它就会使得匹配次数限定为“较少”的一方,例如*的含义是匹配0次或者多次,那么*?就是匹配0次,而不能匹配多次,这就是非贪婪的含义。此外,^和正常字符在一起使用时表示匹配字符的开头,但是在中括号内使用时就成为反向范围的含义,例如[abc]匹配包括a或者b或者c,而[\^abc]的含义是匹配除a\b\c以外的任意字符,下面对特殊字符进行详细说明一下,
字符 | 含义 |
a|b | 匹配a或b |
[abc] | 字符集合,匹配a或b或c |
[^abc] | 反向范围,匹配a、b、c以外任意字符 |
[a-z] | 匹配a-z26个字母 |
[^a-z] | 匹配不在a-z之间的任意字符 |
\b | 匹配单词边界,和^、$类似 |
\B | \b的反义,匹配非单词边界 |
\d | 匹配数字 |
\D | 匹配非数字 |
\s | 匹配任何空白字符,包括空格、制表符、换页符 |
\S | 匹配任何非空白字符 |
\w | 匹配字母、数字、下划线 |
\W | 匹配非字母、数字、下划线 |
\f | 匹配换页符 |
\n | 匹配换行符 |
\r | 匹配回车符 |
\t | 匹配制表符 |
上述就是我们常用的正则表达式符号,可以根据我们的需求,对上述这些字符进行任意的组合,来完成我们的匹配、查询、替换等工作。