1 简介
正则表达式(regex):是一些由字符和特殊符号组成的字符串,它们描述了模式的重复或者表述多个字符,能按照某种模式匹配一系列有相似特征的字符串。
Python通过标准库中的re模块来支持正则表达式。
2 特殊字符和符号(元字符)
2.1 常见正则表达式符号和特殊字符
表示法 | 描述 | 正则表达式示例 |
符号 | ||
literal | 匹配文本字符串的字面值literal | foo |
re1|re2 | 匹配正则表达式re1 或者re2 | foo|bar |
. | 匹配任何字符(除了\n 之外) | b.b |
^ | 匹配字符串起始部分 | ^Dear |
$ | 匹配字符串终止部分 | /bin/*sh$ |
* | 匹配0 次或者多次前面出现的正则表达式 | [A-Za-z0-9]* |
+ | 匹配1 次或者多次前面出现的正则表达式 | [a-z]+\.com |
? | 匹配0 次或者1 次前面出现的正则表达式 | goo? |
{N} | 匹配N 次前面出现的正则表达式 | [0-9]{3} |
{M,N} | 匹配M~N 次前面出现的正则表达式 | [0-9]{5,9} |
[…] | 匹配来自字符集的任意单一字符 | [aeiou] |
[..x−y..] | 匹配x~y 范围中的任意单一字符 | [0-9], [A-Za-z] |
[^…] | 不匹配此字符集中出现的任何一个字符,包括某一范围的字符(如果在此字符集中出现) | [^aeiou], [^A-Za-z0-9] |
(*|+|?|{})? | 用于匹配上面频繁出现/重复出现符号的非贪婪版本(*、+、?、{}) | .*?[a-z] |
(…) | 匹配封闭的正则表达式,然后另存为子组 | ([0-9]{3})?,f(oo|u)bar |
特殊字符 | ||
\d | 匹配任何十进制数字,与[0-9]一致(\D 与\d 相反,不匹配任何非数值型的数字) | data\d+.txt |
\w | 匹配任何字母数字字符,与[A-Za-z0-9_]相同(\W与之相反) | [A-Za-z_]\w+ |
\s | 匹配任何空格字符,与[\n\t\r\v\f]相同(\S 与之相反) | of\sthe |
\b | 匹配任何单词边界(\B 与之相反) | \bThe\b |
\N | 匹配已保存的子组N(参见上面的(…)) | price: \16 |
\c | 逐字匹配任何特殊字符c(即,仅按照字面意义匹配,不匹配特殊含义) | \., \\, \* |
\A(\Z) | 匹配字符串的起始(结束)(另见上面介绍的^和$) | \ADear |
扩展表示法 | ||
(?iLmsux) | 在正则表达式中嵌入一个或者多个特殊“标记”参数(或者通过函数/方法) | (?x),(?im) |
(?:…) | 表示一个匹配不用保存的分组 | (?:\w+\.)* |
(?P<name>…) | 像一个仅由name 标识而不是数字ID 标识的正则分组匹配 | (?P<data>) |
(?P=name) | 在同一字符串中匹配由(?P<name>)分组的之前文本 | (?P=data) |
(?#…) | 表示注释,所有内容都被忽略 | (?#comment) |
(?=…) | 匹配条件是如果…出现在之后的位置,而不使用输入字符串;称作正向前视断言 | (?=.com) |
(?!…) | 匹配条件是如果…不出现在之后的位置,而不使用输入字符串;称作负向前视断言 | (?!.net) |
(?<=…) | 匹配条件是如果…出现在之前的位置,而不使用输入字符串;称作正向后视断言 | (?<=800-) |
(?<!…) | 匹配条件是如果…不出现在之前的位置,而不使用输入字符串;称作负向后视断言 | (?<!192\.168\.) |
(?(id/name)Y|N ) | 如果分组所提供的编号id或别名为name的组匹配到字符,需要匹配Y,否则需要匹配N。|N可以省略 | (?(1)y|x) |
2.2 示例
1) 择一匹配(或) |
bat | bit 匹配字符串bat或者bit
2) 匹配任意单个字符 .
f.o 匹配在字母f和o之间的任意一个字符,例如fao、f2o、f#o等
3) 匹配字符串起始部分 ^或着\A
^From 或者 \AFrom 匹配任何以From作为起始的字符串
4) 匹配字符串结尾部分 $或着\Z
/bin/bash$ 或者/bin/bash\Z 匹配任何以/bin/bash作为结尾的字符串
5) 匹配单词边界 \b与\B
\bthe\b 仅仅匹配单词the
er\b 匹配任何以er结尾的单词,可以匹配never中的er,不能匹配verb中的er
er\B 匹配任何包含但并不以er作为结尾的单词,可以匹配verb中的er,不能匹配never中的er
6) 匹配来自字符集的任意单一字符 []
b[aeiu]t 匹配bat、bet、bit、but
7) 限定范围和否定, 匹配范围中的任意单一字符
[A-Z]、[a-z]、[0-9] 用于表示大写字母、小写字母和数值数字
[ena-c] 匹配e、n、a、b、c中任一字符
[^a-c] 不匹配a、b、c任何一个字符
8) *、+、?、{}
dot? 可匹配do、dot
dot* 匹配0次或者多次t,例:do、dot、dott、dottt等
dot+ 匹配1次或者多次t,例:dot、dott、dottt等
0{2} 可匹配00
0{2,4} 可匹配00、000、0000
- 贪婪匹配
字符串abcddc使用正则ab.*c可匹配abcddc
- 非贪婪匹配
字符串abcddc使用正则ab.*?c可匹配abc
9) 分组 ()
分组的作用:
(1)将某些规律看成是一组,然后进行组级别的重复
(2)分组后,可以通过后向引用简化表达式(\1);后向引用,引用的仅仅是文本内容(引用的是结果),而不是正则表达式
例:
- \d{1,3}.\d{1,3}.\d{1,3}.\d{1,3} 可以把.\ d{1,3}作为一个组,变为\d{1,3}(.\d{1,3}){3}
- <title>.*</title> 可以写成<(title)>.*</\1>,整个表达式<(title)>.*</\1>为第0组,然后从左到右依次分组编号,(title)为第1组
- (\d{1,3})(.\1){3}这个表达式实际匹配是四个数都相同的IP地址,如:123.123.123.123
10) 扩展表示法
尽管使用圆括号,但是只有(?P<name>)表述一个分组匹配,所有其他的都没有创建一个分组
- 匹配时不区分大小写 (?i)
(?iLmsux)
- 匹配不用保存(不捕获)的分组 (?:)
可以在不需要捕获分组的表达式中使用,加快表达式执行速度
<(title)>.*</\1> 如果是(?:title),则\1就不能捕获这个子组了
- 命名组(?<name>…)与调用已匹配的命名组(?P=name)
(?P<num>\d+) 匹配全部由数字组成,num为组名
(?P=num) 注意:调用的是前面命名组里已匹配的内容,也就是说调用后的内容跟前面命名组里匹配的内容是一样的
- 注释(?#)
(?#comment) 不做匹配,只是作为注释
- 断言
(1)匹配<title>xxx</title>中的XXX
想指定xxx前肯定会出现<title>,就用正向后视断言,表达式:(?<=<title>).*
想指定xxx后边肯定会出现</title>,就用正向前视断言,表达式:.*(?=</title>)
两个加在一起,就是(?<=<title>).*(?=</title>)
这样就能匹配到xxx,匹配的内容不包括断言的内容,即完整的匹配就是xxx,不会包含<title>和</title>,子组中也不包含
(2)(?!net) 如果一个字符串后面不是net才做匹配
(3)(?<!192\.168\.) 如果一个字符串之前不是192.168.才做匹配
(4)(?(id/name)Y|N ) 如果分组所提供的编号id或别名为name的组匹配到字符,需要匹配Y,否则需要匹配N。|N可以省略;(\d)?abc(?(1)\d|abc)可以匹配成功字符串为'1abc2'或者'abcabc'。
3 正则表达式与python语言
Python使用re模块支持正则表达式
3.1 使用compile()函数编译正则表达式
Python中使用正则表达式时,re模块内部会做两件事情:
1) 编译正则表达式
2) 用编译后的正则表达式去匹配字符串
尽管推荐预编译,但它并不是必需的。出于效率的考虑,可以预编译正则表达式
import re
string = '123abc'
reCompile = re.compile(r'(\d*)')
print(reCompile.match(string).group())
3.2 使用match()方法匹配字符串
match()函数试图从字符串的起始部分对模式进行匹配。如果匹配成功,就返回一个匹配对象;如果匹配失败,就返回None
3.3 使用search()在字符串中查找(搜索)模式
search()在任意位置对给定正则表达式模式搜索第一次出现的匹配情况
3.4 匹配任意单个字符
3.5 group()和groups()方法
group()要么返回整个匹配对象,要么根据要求返回特定子组
groups()则仅返回一个包含唯一或者全部子组的元组
3.6 使用findall()和finditer()查找每一次出现的位置
1) findall()查询字符串中某个正则表达式模式每一次出现情况,findall()总是返回一个列表
对于一个成功的匹配,每个子组匹配是由findall()返回的结果列表中的单一元素;对于多个成功的匹配,每个子组匹配是返回的一个元组中的单一元素,而且每个元组(每个元组都对应一个成功的匹配)是结果列表中的元素
2) finditer()函数是一个与findall()函数类似但是更节省内存的变体, finditer()返回的是一个迭代
3.7 使用sub()和subn()搜索与替换
sub()和subn()将某字符串中所有匹配正则表达式的部分进行某种形式的替换。subn()还返回一个表示替换的总数,替换后的字符串和表示替换总数的数字一起作为一个拥有两个元素的元组返回。
3.8 在限定模式上使用split()分隔字符串
基于正则表达式的模式分隔字符串,为字符串分隔功能添加一些额外的威力
3.9 扩展符号
1)不区分大小写:(?i)与re.I/IGNORECASE
2)在目标字符串中实现跨行搜索,而不必将整个字符串视为单个实体:(?m)与re.M/MULTILINE
3)表明点号(.)能够用来表示\n符号:(?s)与re.S/DOTALL
4)允许用户通过抑制在正则表达式中使用空白符(除了在字符类中或者在反斜线转义中)来创建更易读的正则表达式:(?x)与re.X/VERBOSE
5)对部分正则表达式进行分组,但不会保存该分组用于后续的检索或者应用:(?:)
6)使用一个名称标识符(?P<name>)和(?P=name),可以使用一个类似风格的\g<name>来检索它们
3.10 Python正则表达式匹配反斜杠”\”
参考https://www.cnblogs.com/longBlogs/p/9718199.html