正则表达式是使用单个字符串来描述、匹配某个句法规则的字符串,通常被用来检索、替换那些符合某个模式的文本。
正则表达式通常是由普通字符(例如a到z)以及特殊字符(称为元字符)组成的文字模式。
所谓元字符,就是用于构建正则表达式的具有特殊含义的字符。
常用的元字符如下:
元字符 | 说明 |
---|---|
. | 匹配除换行符之外的任意字符。 |
\w | 匹配字母或数字或下划线或汉字。 |
\s | 匹配任意空白符。 |
\d | 匹配数字。 |
\b | 匹配单词的开始或结束。 |
^ | 匹配字符串的开始。 |
$ | 匹配字符串的结束。 |
正则表达式中的限定符:
语法 | 说明 |
---|---|
* | 重复零次或更多次。 |
+ | 重复一次或更多次。 |
? | 重复零次或一次。 |
{n} | 重复n次。 |
{n,} | 重复n次或更多次。 |
{n,m} | 重复n到m次,其中m不能大于n,两数与逗号之间不能有空格。 |
以上这些限定符,可以匹配指定个数的字符,在能够匹配的范围之内,尽可能多的匹配。
在正则表达式中像.*?
等字符都被赋予了特殊的含义,如果我们要匹配这些字符的时候,就需要使用\
来取消这些字符的特殊含义,当然要匹配\
的时候,需要使用\\
来进行匹配。
如果我们要匹配指定范围内的任意一个字符,我们可以选择使用字符组来进行匹配,例如,我们要匹配cat、Cat、hat、Hat
,可以选择使用表达式[CcHh]at
来进行匹配。另外也可以指定某个范围不用一一列举,如:[0-5]
表示的是要匹配0到5这几个数字,当然字母也可以使用-
来指定范围,如[a-f]
。
正则表达式中的分枝条件指的是有几种不同的规则,如果满足其中一种规则就应该匹配出来。具体的实现方法是通过|
来分隔不同的匹配模式。
例如我们要匹配三位数字或五位数字,可以使用如下方式:\d{5}|\d{3}
,那么为什么要把5写在前面呢,因为在使用分枝条件时有一个顺序问题,如果将3和5换一下位置,这个表达式将不能够匹配出五位数字,在匹配分枝条件时,将会从左到右的测试每个条件,如果满足了某个分枝的话,就不会再去管其他条件了。
在1.2
中已经说了如何重复单个字符(直接在字符后面加上限定符),那么如果想要重复多个字符怎么办呢,可以选择使用分组的方式,用小括号来指定子表达式,然后在小括号后面加上限定符就可以指定这个子表达式的重复次数了。例如我们要匹配一个IP
地址xxx.xxx.xxx.xxx
,这里我们可以将前三个部分看做相同的部分为xxx.
,然后将最后一个xxx
看做单独的一部分,这样我们就可以使用分组来进行匹配了,表达式如下:((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)
。
有时候我们需要匹配不属于某个能简单定义的字符类的字符,这时候我们就需要用到反义,常用的反义代码如下:
代码 | 说明 |
---|---|
\W | 匹配任意不是字母,数字,下划线,汉字的字符。 |
\S | 匹配任意不是空白符的字符。 |
\D | 匹配任意非数字的字符。 |
\B | 匹配不是单词开头或结束的字符。 |
[^x] | 匹配除了x以外的任意字符。 |
[^adf] | 匹配除了adf这几个字母以外的任意字符。 |
使用小括号指定一个子表达式后,匹配这个子表达式的文本(也就是此分组捕获的内容)可以在表达式或其它程序中作进一步的处理。默认情况下,每个分组会自动拥有一个组号,规则是:从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。
后向引用用于重复搜索前面某个分组匹配的文本。例如,\1
代表分组1匹配的文本。
表达式:\b(\w+)\b\s+\1\b
可以用来匹配重复的单词,如:go go
等。
常用分组语法:
分类 | 代码\语法 | 说明 |
---|---|---|
捕获 | (exp) | 匹配exp,并捕获文本到自动命名的组里。 |
(?exp) | 匹配exp,并捕获文本到名称为name的组里,也可以写成(?'name’exp), 在python中要写成(?P |
|
(?:exp) | 匹配exp,不捕获匹配的文本,也不给此分组分配组号。 | |
零宽断言 | (?=exp) | 匹配exp前面的位置。 |
(?<=exp) | 匹配exp后面的位置。 | |
负向零宽断言 | (?!exp) | 匹配后面跟的不是exp的位置。 |
(? | 匹配前面不是exp的位置。 | |
注释 | (?#comment) | 用于提供注释让人阅读。 |
用于查找在某些内容(但并不包括这些内容)之前或之后的东西,也就是说它们像\b,^,$那样用于指定一个位置,这个位置应该满足一定的条件(即断言),因此它们也被称为零宽断言。在上面已经介绍过了零宽断言的语法。
以(?=exp)
(它又叫零宽度正预测先行断言)为例,如果我们要匹配以ing
结尾的单词的前半部分,则可以使用如下正则表达式来进行匹配:\b\w+(?=ing\b)
。例如匹配reading looking
,它会匹配出read
和look
。其它零宽断言语法的使用类似,只是位置有所区别。
(?<=exp)
又称为零宽度正回顾后发断言。
与零宽断言相反,负向零宽断言匹配的是不满足某条件的位置。
(?!exp)
称为零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp
。
(?称为零宽度负回顾后发断言,断言此位置的前面不能匹配表达式
exp
。
要包含注释的话,最好是启用“*忽略模式里的空白符*”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符,这就被称为贪婪匹配。而懒惰匹配是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式。
懒惰限定符:
代码\语法 | 说明 |
---|---|
*? | 重复任意次,但尽可能少重复。 |
+? | 重复1次或更多次,但尽可能少重复。 |
?? | 重复0次或1次,但尽可能少重复。 |
{n,m}? | 重复n到m次,但尽可能少重复。 |
{n,}? | 重复n次以上,但尽可能少重复。 |
Python
中常用的正则表达式选项:
名称 | 说明 |
---|---|
re.IGNORECASE |
匹配时不区分大小写。 |
re.MULTILINE |
更改^和 的 含 义 , 使 它 们 分 别 在 任 意 一 行 的 行 首 和 行 尾 匹 配 , 而 不 仅 仅 在 整 个 字 符 串 的 开 头 和 结 尾 匹 配 。 ( 在 此 模 式 下 , 的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下, 的含义,使它们分别在任意一行的行首和行尾匹配,而不仅仅在整个字符串的开头和结尾匹配。(在此模式下,的精确含意是:匹配\n之前的位置以及字符串结束前的位置)。 |
re.DOTALL |
更改. 的含义,使它与每一个字符匹配(包括换行符\n)。 |
re.VERBOSE |
忽略表达式中的非转义空白并启用由#标记的注释。 |
re.DEBUG |
显示编译表达式的 debug 信息。 |
有时我们需要匹配像( 100 * ( 50 + 15 ) )
这样的可嵌套的层次性结构,这时简单地使用\(.+\)
则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。为了能够匹配出配对括号之间的内容,需要用到以下语法:
< #最外层的左括号
[^<>]* #最外层的左括号后面的不是括号的内容
(
(
(?'Open'<) #碰到了左括号,在黑板上写一个"Open"
[^<>]* #匹配左括号后面的不是括号的内容
)+
(
(?'-Open'>) #碰到了右括号,擦掉一个"Open"
[^<>]* #匹配右括号后面不是括号的内容
)+
)*
(?(Open)(?!)) #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败
> #最外层的右括号
这是一个匹配尖括号中间内容的代码。但是这在python中是不能使用的,Python不支持平衡组。
以上内容参考自:!正则表达式30分钟入门教程
re
模块是Python
中自带的模块,其中封装了对正则表达式进行处理的一些函数。
常用函数
re.compile(pattern[, flags])
:根据包含正则表达式的字符串创建模式对象,可以实现更有效率的匹配,其中flag
参数可以指定处理选项,如:忽略大小写、忽略空格等。在re.search()
等函数中直接使用字符串进行操作时,python会将字符串转换成模式对象,而使用re.compile()
完成一次转换后,在每次使用模式的时候不用重复进行转换。可以直接使用模式对象加点号调用search、match
等函数。re.match()
:尝试从字符串的开头匹配一个模式,匹配成功会返回一个匹配对象,否则返回None
。re.search()
:扫描整个字符串并返回第一个成功的匹配,匹配成功返回一个匹配对象,否则返回None
。re.findall()
:查找整个字符串中所有与正则表达式匹配的部分。re.split()
:按正则表达式将字符串分割开。re.sub(pattern, repl, string, count=0, flags=0)
:根据正则表达式替换子串,返回替换后的字符串。repl
可以是字符串,也可以是可调用的函数; 如果是字符串,则处理其中的反斜杠转义。 如果它是可调用的函数,则将其传递给match对象,并且必须返回要使用的替换字符串。re.subn(pattern, repl, string, count=0, flags=0)
:根据正则表达式替换子串,返回一个元组,包含替换后的字符串和替换的次数。repl
可以是字符串,也可以是可调用的函数; 如果是字符串,则处理其中的反斜杠转义。 如果它是可调用的函数,则将其传递给match对象,并且必须返回要使用的替换字符串。re.finditer()
:与findall()
函数功能相同,只是该方法返回一个迭代器。re.fullmatch()
:从头到尾完全匹配字符串,如果完全匹配则返回一个匹配对象,否则返回None
。re.escape()
:对字符串中所有可能被解释为正则运算符的字符进行转义的应用函数,除了\w均做转义。re.purge()
:清除正则表达式缓存。上述函数中返回的匹配对象re.MatchObject
可以调用的方法:
group()
:返回匹配到的字符串,如果有分组,返回分组中的内容。start()
:返回匹配开始的位置。end()
:返回匹配结束的位置。span()
:返回一个元组包含匹配开始和结束位置。正则表达式常用的修饰符-可选标志(函数中的flags参数)
正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M
被设置成I
和M
标志:
修饰符 | 描述 |
---|---|
re.I |
使匹配对大小写不敏感 |
re.L |
做本地化识别(locale-aware)匹配 |
re.M |
多行匹配,影响 ^ 和 $ |
re.S |
使 . 匹配包括换行在内的所有字符 |
re.U |
根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X |
该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 |
如有错误欢迎批评指正!!