简介
正则是一个字符串规则,本身也是一个字符型,用来检查一个串是否含有字串。可以做精确匹配,模糊匹配,进行字符串替换,切割,尤其是在造数据,分析日志时用的非常多。
python中处理正则表达式的模块是re模块,正则表达式由一些普通字符和一些元字符组成,普通字符包括大小写字母、数字和打印符号,而元字符是具有特殊含义的字符。
正则表达式模式
正则表达式大致的匹配过程是:
拿正则表达式依次和字符串或者文本中的字符串做比较,如果每一个字符都匹配,则匹配成功,只要有一个匹配不成功的字符,则匹配不成功。模式字符串使用特殊的语法来表示一个正则表达式:
- 字母和数字匹配它们自身;
- 多数字母和数字前加一个反斜杠(\)时会有特殊含义;
- 特殊的标点符号,只有被转义以后才能匹配自身;
- 反斜杠本身要用反斜杠来转义
注意:
- 由于正则表达式通常版本反斜杠等特殊字符,所以最好使用原始字符串来表示他们。如:r’\d’等价于’\\d’,表示匹配一个数字
- 正则表达式中数量词默认都是贪婪的,会尽可能多的去匹配满足的字符串,但是如果在后面加上问号’?’,就可以屏蔽贪婪模式,表示匹配尽可能少的字符。如:’xyyyyzs’,使用正则’xy*’,就会得到'xyyyy',如果使用’xy*?’,会得到'x'
特殊表达式含义
符号 | 含义 | 举例 |
一般字符(匹配自身) | ||
.(点) | 匹配除换行符之外的任意一个字符,DOTALL模式中可以匹配换行符 | a.c可以匹配abc |
\(反斜杠) | 转义一个特殊的字符,使这个字符表示原来字面上的意思。如"\$",表示原字符$,而不是正则表达式中表示匹配行尾的意思。 | a\.c匹配a.c |
预定义字符集(可以写在[]中) | ||
[...] 方括号 | 匹配括号中出现的任意单个字符 | a[123]b匹配a1b、a2b、a3b、a12b等 |
[^...] | 不匹配方括号中列出的单个字符(注意只能针对单个字符) | [^ab]匹配除a和b之外的字符 |
\d | 匹配中任意一个数字,范围为[0-9] | a\dc可以匹配a1c、a2c等 |
\D | 匹配任意一个非数字字符,等价于[^\d] | 1\D2可匹配1a2 |
\s | 匹配任意一个空白字符:[<空格>\t\r\n\v\f] | a\sf匹配a f |
\S | 匹配任意一个非空白字符,等价于[^\s] | a\Sg匹配agg等 |
\w | 匹配一个字母或数字,字符范围:[A-Za-z0-9] | 1\wt可以匹配1at等 |
\W | 非单词字符,等价于[^\w] | a\Wb可以匹配a@b等 |
数量字符集(用在字符或分组符(...)之后,非贪婪匹配*? +?) | ||
*(星号) | 匹配前一个字符0次1次或多次 | abc*可以匹配ab、abc、abcc等 |
+(加号) | 匹配前一个字符1次或多次 | cde+可匹配cde、cde等 |
?(问号) | 匹配前一个字符0次或1次 | fgh?匹配结果fg、fgh |
{m} | 匹配前一个字符m次 | qc{3}匹配结果qccc |
{m,n} | 匹配前一个字符m到n次 {m,}匹配前一个字符至少m次 {,n}匹配前一个字符0到n次,最多n次 | 1{2,5}ac匹配结果11ac、111ac、1111ac、11111ac |
符号 | 含义 | 举例 |
|
边界匹配符 | |||
^(托字符) | 匹配字符串开头,如果是多行则匹配每一行的开头。在[...]中,^表示否定,如非字母[^a-zA-Z],非数字[^0-9] | ^123匹配123 a[^0-9]b可匹配aab等 |
|
$(美元符) | 匹配字符串或一行的结尾,如果是多行则匹配每一行的结尾 | abc$匹配abc |
|
\A | 匹配字符串开始,如果存在换行,将字符当作一个整体 | \A12AC匹配12AC |
|
\b | 匹配一个单词的边界,也就是指单词和空格间的位置 | \bst匹配a test中的'st',但不匹配'tester'中的''st | |
\B | [^\b],表示匹配非单词边界 | \Bst可以匹配'tester'而不能匹配'test' | |
\Z | 匹配字符串结束,如果存在换行,将字符当作一个整体 | abt\Z匹配abt |
|
逻辑匹配符 | |||
|(或) | |或匹配符,表达左右正则表达式任意匹配一个。如果左边的表达式匹配上了,匹配结束,不再匹配右边的表达式。该符号一般放在()中使用,如果没在圆括号中则它的范围是整个正则表达式。 | (12|34)匹配12或34 |
|
分组匹配 | |||
(...) | 后向引用。用()括起来的正则表达式将被作为一个分组,从正则表达式的左边依次算起,有多少个左括号'(',就有多少个分组,分组的编码从1依次加1,无论是括号中嵌套括号。并且分组表达式作为一个整体,后可接数量词。 | (xyz){2}满足xyzxyz x(12|34)y匹配x12y或x34y |
|
\<number> | 引用分组匹配到的分组编号为<number>的字符串 | 如:\1...\9 |
|
(?P<name>...) | 命名分组,除了默认的分组编号外再指定一个别名分组 注意:P是大写 | ||
(?P=name) | 引用别名为name的分组匹配,这个是在正则表达式中引用,表示匹配重复的字符串,也可以使用编号引用。 注意:P是大写 | ||
特殊匹配符(不能作为分组使用) | |||
(?:...) | |||
(?!pattern) | 前向否定断言语法,表示否定开头。只能用在正则表达式的开头,pattern是匹配模式,它后面的内容需要不匹配该正则表达式才匹配成功。 | ||
(?<!pattern) | 后向否定断言语法,表示否定结尾,前面的内容需要不匹配该pattern模式才匹配成功。 | ||
(?=pattern) | 前向肯定断言语法,需要匹配pattren模式才能匹配成功,表示肯定前面的字符内容。 | ||
(?<=pattern) | 后向肯定断言语法,需要匹配pattern模式才能匹配成功,表示肯定后面的字符内容。 | ||
(?#...) | #后面的内容将被作为注释而忽略 |
.(点)
匹配除换行符之外的所有字符。可以在DOTALL模式中可以匹配换行符。
>>> import re
>>> re.match(r'.','and23__09')
<_sre.SRE_Match object; span=(0, 1), match='a'>#返回的是匹配结果的对象,span表示是是匹配的开始位置和结束位置,开区间
>>> re.match(r'..','and23__09')
<_sre.SRE_Match object; span=(0, 2), match='an'>
>>> re.match(r'..........','and23__09')#匹配的个数比字符中多的时候,返回的是None
>>> print(re.match(r'.','\n'))
None
>>> re.match(r'.','\n',re.DOTALL)#可以匹配换行符
<_sre.SRE_Match object; span=(0, 1), match='\n'>
多行字符串的两种实现方式:
三引号
>>> '''hello
... python
... 123'''
'hello\npython\n123'
单引号里面包含\n
>>> print('abc\ndef')
abc
def
\(反斜杠)
>>> print(re.match(r"\.",".a\nc"))#匹配 .
<_sre.SRE_Match object; span=(0, 1), match='.'>
>>> print(re.match(r"\\","\\a\nc"))#匹配 \本身
<_sre.SRE_Match object; span=(0, 1), match='\\'>
[...]方括号:
匹配括号中指定的某一个字符,但是只能匹配一个字符。
>>> print(re.match(r"[abc]","axxx")) #匹配字符a
<_sre.SRE_Match object; span=(0, 1), match='a'>
>>> print(re.match(r"[abc]","bxxx")) #匹配字符b
<_sre.SRE_Match object; span=(0, 1), match='b'>
>>> print(re.match(r"[abc]","cxxx")) #匹配字符c
<_sre.SRE_Match object; span=(0, 1), match='c'>
[^...]
不匹配括号中指定的任何一个字符,但是只能匹配一个字符(注意^在方括号里面表示非,在方括号外面表示开头匹配)
>>> print(re.match(r"[^abc]","hxxx")) #匹配开头是非abc之外的任意一个字符
<_sre.SRE_Match object; span=(0, 1), match='h'>
>>> print(re.search(r"abc","sssssabc")) #匹配abc,可以不是开头
<_sre.SRE_Match object; span=(5, 8), match='abc'>
>>> print(re.search(r"^abc","sssssabc"))#匹配以abc开头的字符
None
>>> print(re.match(r"\d","123"))#匹配一次
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> print(re.match(r"\d+","123"))#匹配一次或多次
<_sre.SRE_Match object; span=(0, 3), match='123'>
>>> print(re.match(r"\d*","123"))#匹配0次或多次
<_sre.SRE_Match object; span=(0, 3), match='123'>
\d
匹配中任意一个数字,范围为[0-9]
>>> re.match(r"\d","123").group()
'1''
\D
匹配任意一个非数字字符,等价于[^\d]
>>> re.match(r"\D+","a123").group()
'a'
>>> re.match(r"\D+","abc123").group()
'abc'
\s
匹配任意一个空白字符:[<空格>\t\r\n\v\f]
>>> re.search(r'\s','anb \t \r \n')
<_sre.SRE_Match object; span=(3, 4), match=' '>
>>> re.search(r'\s+','anb \t \r \n')
<_sre.SRE_Match object; span=(3, 9), match=' \t \r \n'>
\S
匹配任意一个非空白字符,等价于[^\s]
>>> re.findall(r"\S+","ab cd\t ef\nhi")
['ab', 'cd', 'ef', 'hi']
>>> "".join(re.findall(r"\S+","ab cd\t ef\nhi")) #去掉了字符串中所有的空白字符
'abcdefhi'
\w
匹配一个字母,数字和下划线,字符范围:[A-Za-z0-9_]
>>> re.search(r'\w','12bsc_-')
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>>
>>> re.search(r'\w+','12bsc_-')
<_sre.SRE_Match object; span=(0, 6), match='12bsc_'>
>>>
\W
非字母,数字和下划线,等价于[^\w]
>>> re.search(r'\W+','12bsc_-')
<_sre.SRE_Match object; span=(6, 7), match='-'>
>>> re.search(r'\W+','a@b')
<_sre.SRE_Match object; span=(1, 2), match='@'>
*
匹配一个字符0次或多次,注意正则默认的贪婪性,贪婪性指的是在满足匹配的条件下再继续贪婪更多的匹配
>>> print(re.match(r"\d*","123"))
<_sre.SRE_Match object; span=(0, 3), match='123'>
>>> print(re.match(r"\d*?","123")) #用问号抑制贪婪,*最小是0次匹配
<_sre.SRE_Match object; span=(0, 0), match=''>
>>> print(re.match(r"\d+?","123"))#用问号抑制贪婪,+最小是1次匹配
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> print(re.search(r'\d*','abc123'))
<_sre.SRE_Match object; span=(0, 0), match=''>
search有匹配就会返回,字符串不是数字开头,匹配0次,所以返回的是空
?
匹配一个字符0次或1次,?用在数量词(*/+/{m}/{m,n})后面才表示抑制贪婪性。
>>> re.search(r"\d?","a7").group() #不是以数字开头,匹配了0次,所以返回空字符
''
>>> re.search(r"\d?","7").group() #以数字开头,匹配了1次,所以返回7
'7'
+
匹配一个字符1次或多次,注意正则默认的贪婪性。
>>> s = "abc123dee"
>>> re.search(r'\d+',s)
<_sre.SRE_Match object; span=(3, 6), match='123'>
>>> re.search(r'\d+',s).group()
'123'
>>> re.search(r"\d+","7").group()
'7'
>>> print(re.match(r"\d+?","123"))#用问号抑制贪婪,+最小是1次匹配
<_sre.SRE_Match object; span=(0, 1), match='1'>
{}
匹配次数
{m}:匹配前一个字符m次
{m,n}:匹配前一个字符m到n次
{m,}匹配前一个字符至少m次
{,n}匹配前一个字符0到n次,最多n次
>>> re.search(r'\d{2}',"abc123dee").group()
'12'
>>> re.search(r"\d{3}","123456789").group()
'123'
>>> re.search(r"\d{1,3}","123456789").group() #贪婪性
'123'
>>> re.search(r"\d{1,3}?","123456789").group()
'1'
^(脱字符)
匹配字符串开头,如果是多行则匹配每一行的开头。在[...]中,^表示否定,如非字母[^a-zA-Z],非数字[^0-9]
>>> re.search(r"^abc","dddabc")
>>> re.search(r"^abc","abcabc")
<_sre.SRE_Match object; span=(0, 3), match='abc'>
>>> re.search(r"^abc","abcde\nabc")
<_sre.SRE_Match object; span=(0, 3), match='abc'>
$(美元符)
匹配字符串或一行的结尾,如果是多行则匹配每一行的结尾
>>> re.search(r"^\d+","133dddabc")
<_sre.SRE_Match object; span=(0, 3), match='133'>
>>> re.search(r"\d+$","133dddabc5555")
<_sre.SRE_Match object; span=(9, 13), match='5555'>
>>> re.search(r"^123$","123")
<_sre.SRE_Match object; span=(0, 3), match='123'>
\A
非多行匹配的时候等价于^,多行匹配的是\A将整个字符串看做一个整体匹配,而^能够则匹配每一行的结尾
>>> re.search(r"\Aabc","abcabc")
<_sre.SRE_Match object; span=(0, 3), match='abc'>
>>> s = '124\n453\n'
>>> re.search(r'^\d',s)
<_sre.SRE_Match object; span=(0, 1), match='1'>
>>> re.findall(r'^\d',s)
['1']
>>> re.findall(r'^\d',s,re.M) #匹配多行文件每行的结尾
['1', '4']
>>> re.findall(r'\A\d',s,re.M) #即使加了re.M,使用\A时仍然是将字符串看做一个整体
['1']
>>> re.findall(r'\A\d',s)#使用\A时仍然是将字符串看做一个整体
['1']
\Z
非多行时等价于$,多行匹配\Z将整个字符串看做一个整体匹配,而$能够则匹配每一行的结尾。
>>> re.search(r"\A123\Z","123")
<_sre.SRE_Match object; span=(0, 3), match='123'>
>>> s = '124\n453\n'
>>> re.search(r'\d$',s)
<_sre.SRE_Match object; span=(6, 7), match='3'>
>>> re.search(r'\d\Z',s) #没有匹配成功
>>> re.findall(r'\d$',s)
['3']
>>> re.findall(r'\d$',s,re.M) #匹配每一行的结尾
['4', '3']
>>> re.findall(r'\d\Z',s)
[]
>>> re.findall(r'\d\Z',s,re.M)#换行前的结束字符也不能匹配
[]
>>> s = '124\n453'
>>> re.findall(r'\d\Z',s,re.M)
['3']
>>> re.findall(r'\d\Z',s)
['3']
()分组
用()括起来的正则表达式将被作为一个分组,从正则表达式的左边依次算起,有多少个左括号'(',就有多少个分组,分组的编码从1依次加1,无论是括号中嵌套括号。并且分组表达式作为一个整体,后可接数量词。
>>> re.search(r"\d(\D+)\d","1abc3").group(1)
'abc'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(1)
'1'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(2)
'abc'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(2)
'abc'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(3)
'3'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group()#表示正则表达式匹配的全部内容,等价于group(0)
'1abc3'
>>> re.search(r"(\d)(\D+)(\d)","1abc3").group(0)
'1abc3'