正则
就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。
下图为常用匹配模式(元字符)
需要注意的是:一段正则表达式,先交由python解释器来解释,然后再交由re模块执行解释,所以除了要注意正则表达式的元字符格式,也要注意python解释器对一些特殊符号的特殊意义.
#\n在python解释器中是换行的意思,会被优先解释,然后在交由re模块解释
例如:
print(‘ab\nc‘)
运行结果:
ab
c
#如果不想经过python解释器解释,直接原封不动的将字符串交给re模块,加一个r即可
例如:
print(r‘ab\nc‘)
运行结果:
ab\nc
\w:匹配字符数字及下划线
\W:匹配非字母数字及下划线
a = ‘as213df_*|‘
b = ‘a_b a3b aEb a*b‘
print(re.findall(‘\w‘, a))
print(re.findall(‘\W‘, a))
print(re.findall(‘a\wb‘, b))
运行结果:
[‘a‘, ‘s‘, ‘2‘, ‘1‘, ‘3‘, ‘d‘, ‘f‘, ‘_‘]
[‘*‘, ‘|‘]
[‘a_b‘, ‘a3b‘, ‘aEb‘]
\s:匹配任意空白字符,包括[\t\n\t\f]
\S:匹配任意非空字符
print(re.findall(‘\s‘, ‘a b\nc\td‘))
print(re.findall(‘\S‘, ‘a b\nc\td‘))
运行结果:
[‘ ‘, ‘\n‘, ‘\t‘]
[‘a‘, ‘b‘, ‘c‘, ‘d‘]
\d:匹配任意数字,等价于[0-9]
\D:匹配任意非数字
print(re.findall(‘\d‘,‘a123bcdef‘))
print(re.findall(‘\D‘,‘a123bcdef‘))
运行结果:
[‘1‘, ‘2‘, ‘3‘]
[‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘]
\A:匹配以字符串开始,等同于^
\z:匹配字符串结束,等同于$
\Z:匹配字符串结束,如果存在换行符,则仅匹配到换行符前的字符串,等同于$
print(re.findall(‘\Ahe‘, ‘hello, world, 2017‘))
print(re.findall(‘2017\Z‘, ‘hello, world, 2017\n2017‘))
运行结果:
[‘he‘]
[‘2017‘]
\G:匹配最后匹配完成的位置
\n:匹配一个换行符
\t:匹配一个制表符
print(re.findall(‘\n‘,‘a123\nbcdef‘))
print(re.findall(‘\t‘,‘a123\tbc\td\tef‘))
运行结果:
[‘\n‘]
[‘\t‘, ‘\t‘, ‘\t‘]
^:匹配字符串的开头
$:匹配字符串的末尾
print(re.findall(‘h‘,‘hello egon hao123‘))
print(re.findall(‘^h‘,‘hello egon hao123‘))
print(re.findall(‘^h‘,‘ello egon hao123‘))
运行结果:
[‘h‘, ‘h‘]
[‘h‘]
[]
print(re.findall(‘3‘,‘e3ll3o e3gon hao123‘))
print(re.findall(‘3$‘,‘e3ll3o e3gon hao123‘))
print(re.findall(‘3$‘,‘e3ll3o e3gon hao123asdf‘))
运行结果:
[‘3‘, ‘3‘, ‘3‘, ‘3‘]
[‘3‘]
[]
[...]:匹配中括号内任意一个字符,如a[123]b,a1b,a2b,a3b等都会匹配
[m-n]:匹配一个范围
[...*-]:匹配*和-,特殊符号要写在开头或结尾
[]:内写什么就匹配什么,原生字符
print(re.findall(‘a[1,2\n]c‘,‘a2c a,c abc a1c a*c a|c abd aed a\nc‘))
print(re.findall(‘a[0-9]c‘,‘a2c a,c abc a1c a*c a|c abd aed a\nc‘))
print(re.findall(‘a[0-9a-zA-Z*-]c‘,‘a1c abc a*c a-c aEc‘))
运行结果:
[‘a2c‘, ‘a,c‘, ‘a1c‘, ‘a\nc‘]
[‘a2c‘, ‘a1c‘]
[‘a1c‘, ‘abc‘, ‘a*c‘, ‘a-c‘, ‘aEc‘]
[^...]:取反,不再[]中的字符,在括号外则代表取开头
print(re.findall(‘a[^0-9]c‘,‘a1c abc a*c a-c aEc‘))
运行结果:
[‘abc‘, ‘a*c‘, ‘a-c‘, ‘aEc‘]
., *, +, ?, {m,n} :表示重复匹配
.:匹配任意1个字符,除了换行符
如果要匹配换行符,需要在findall后面加参数re.S,即re.findall(‘‘, ‘‘, re.S)
print(re.findall(‘a.c‘,‘abc a1c a*c a|c abd aed ac‘))
print(re.findall(‘a.c‘,‘abc a1c a*c a|c abd aed a\nc‘,re.S))
运行结果:
[‘abc‘, ‘a1c‘, ‘a*c‘, ‘a|c‘]
[‘abc‘, ‘a1c‘, ‘a*c‘, ‘a|c‘, ‘a\nc‘]
*:匹配0个或多个,匹配尽可能多的字符
print(re.findall(‘ab*‘,‘a‘))
print(re.findall(‘ab*‘,‘abbbbbb‘))
print(re.findall(‘ab*‘,‘bbbbbb‘))
运行结果:
[‘a‘]
[‘abbbbbb‘]
[]
+:匹配1个或多个
print(re.findall(‘ab+‘,‘a‘))
print(re.findall(‘ab+‘,‘abbbbbb‘))
print(re.findall(‘ab+‘,‘bbbbbb‘))
print(re.findall(‘ab[123]+‘,‘ab11111111 ab2 ab3 abc1 ab11112 ab12222 ab1233333‘)) #ab1+,ab2+,ab3+,ab[123][123][123]
运行结果:
[]
[‘abbbbbb‘]
[]
[‘ab11111111‘, ‘ab2‘, ‘ab3‘, ‘ab11112‘, ‘ab12222‘, ‘ab1233333‘]
?:匹配0个或1个,非贪婪方式,匹配尽可能少的字符
print(re.findall(‘ab?‘,‘a‘)) #[‘a‘]
print(re.findall(‘ab?‘,‘abbb‘)) #[‘ab‘]
print(re.findall(‘ab?c‘,‘ac abc aec a1c‘))
运行结果:
[‘a‘]
[‘ab‘]
[‘ac‘, ‘abc‘]
{n}:精确匹配n次
{n,m]:匹配n到m次由前面的正则表达式定的片段,贪婪方式
print(re.findall(‘ab{3}‘,‘ab1 abbbbbbbb2 abbbbb3 ab4 ab122‘)) #出现3次
print(re.findall(‘ab{3,4}‘,‘ab1 abbb123 abbbb123 abbbbbt‘)) #出现3次到4次
print(re.findall(‘ab{3,}‘,‘ab1 abbb123 abbbb123 abbbbbt‘)) #出现3次到无穷次
print(re.findall(‘ab{0,}‘,‘a123123123 ab1 abbb123 abbbb123 abbbbbt‘)) #出现0次到无穷次,类似*
print(re.findall(‘ab{1,}‘,‘a123123123 ab1 abbb123 abbbb123 abbbbbt‘)) #出现1次到无穷次,类似+
运行结果:
[‘abbb‘, ‘abbb‘]
[‘abbb‘, ‘abbbb‘, ‘abbbb‘]
[‘abbb‘, ‘abbbb‘, ‘abbbbb‘]
[‘a‘, ‘ab‘, ‘abbb‘, ‘abbbb‘, ‘abbbbb‘]
[‘ab‘, ‘abbb‘, ‘abbbb‘, ‘abbbbb‘]
():匹配括号内的表达式,也表示一个组,‘?:‘固定格式
print(re.findall(‘ab+‘,‘ababab123‘))
print(re.findall(‘(ab)+123‘,‘ababab123‘)) #[‘ab‘],匹配到末尾的ab123中的ab,不太明白
print(re.findall(‘(?:ab)+123‘,‘ababab123‘)) #findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容
运行结果:
[‘ab‘, ‘ab‘, ‘ab‘]
[‘ab‘]
[‘ababab123‘]
a|b:匹配a或b
print(re.findall(‘compan(y|ies)‘, ‘Too many companies have gone bankrupt, and the next one is my company‘))
print(re.findall(‘compan(?:y|ies)‘, ‘Too many companies have gone bankrupt, and the next one is my company‘))
运行结果:
[‘ies‘, ‘y‘]
[‘companies‘, ‘company‘]
-------------->
.*:任意长度的任意字符,贪婪匹配
print(re.findall(‘a.*c‘,‘ac abc aec a1c‘)) #开头是a,最后是c
运行结果:
[‘ac abc aec a1c‘] #一个值
.*?:非贪婪匹配,?表示将.*转换为非贪婪模式
print(re.findall(‘a.*?c‘,‘ac abc aec a1c‘))
print(re.findall(‘a.*?c‘,‘ac abc a111111111c a\nc a1c‘,re.S))
运行结果:
[‘ac‘, ‘abc‘, ‘aec‘, ‘a1c‘] #列表多个值
[‘ac‘, ‘abc‘, ‘a111111111c‘, ‘a\nc‘, ‘a1c‘] #列表多个值
正则在线调试工具:tool.oschina.net/regex/
re模块方法:
import re
.group(n):获取指定数据
content=‘Hello 123 456 World_This is a Regex Demo‘
res=re.match(‘^Hello\s(\d+)\s(\d+)\s.*Demo‘,content)
print(res.group()) #取所有匹配的内容
print(res.group(1)) #取匹配的第一个括号内的内容
print(res.group(2)) #去陪陪的第二个括号内的内容
运行结果:
Hello 123 456 World_This is a Regex Demo
123
456
re.findall():遍历所有,返回满足条件的结果,放在列表里
print(re.findall(‘a‘, ‘ababb ab abababbaab‘))
运行结果:
[‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘a‘, ‘a‘]
re.search():只找到第一次匹配到的条件,返回一个包含匹配信息的对象,该对象可通过调用group()方法来得到匹配的字符串,没有匹配则返回None
print(re.search(‘a‘, ‘ababb ab abababbaab‘))
print(re.search(‘a‘, ‘ababb ab abababbaab‘).group())
运行结果:
<_sre.SRE_Match object; span=(0, 1), match=‘a‘>
a
re.match():同search(^),从字符串开头进行匹配查找,没有则返回None
print(re.match(‘a‘, ‘ababb ab abababbaab‘).group())
print(re.match(‘a‘, ‘babb ab abababbaab‘))
print(re.search(‘^a‘, ‘ababb ab abababbaab‘).group())
运行结果:
a
None
a
--->re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配
re.split(): 分割
print(re.split(‘[ab]‘, ‘abcd‘))
#先按‘a‘分割得到‘‘和‘bcd‘,再对‘‘和‘bcd‘分别按‘b‘分运行结果:运行结果:
[‘‘, ‘‘, ‘cd‘]
re.sub(‘查找条件‘,‘替换内容‘,‘查找内容字符串‘,n):查找匹配条件并替换
print(‘===>‘,re.sub(‘a‘,‘A‘,‘alex make love‘)) #不指定n,默认替换所有
print(‘===>‘,re.sub(‘a‘,‘A‘,‘alex make love‘,1)) #n为1,表示匹配1次
print(‘===>‘,re.sub(‘a‘,‘A‘,‘alex make love‘,2)) #n为2,表示匹配2次
print(‘===>‘,re.sub(‘^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$‘,r‘\5\2\3\4\1‘,‘alex make love‘))
#\w+任意多个字母,\s任意1个空白字符,\5\2\3\4\1,5表示第5个()分组内容,4表示第4个分组内容,以此类推
print(‘===>‘,re.subn(‘a‘,‘A‘,‘alex make love‘)) #统计总共替换的次数
print(re.sub(‘^a‘,‘A‘,‘alex make love‘)) #匹配开头,替换为大写
print(re.sub(‘^(\w+)(\s)(\w+)(\s)(\w+)‘,r‘\5\2\3\4\1‘,‘alex make love‘))
print(re.sub(‘^(\w+)(\s+)(\w+)(\s+)(\w+)‘,r‘\5‘,‘alex make love‘)) #\s+匹配多个空白字符
print(re.sub(‘^(\w+)(\W+)(\w+)(\W+)(\w+)‘,r‘\5\2\3\4\1‘,‘alex " \ + = make ----/== love‘)) #\W+匹配多个非字母数字下划线
运行结果:
===> Alex mAke love
===> Alex make love
===> Alex mAke love
===> love make alex
===> (‘Alex mAke love‘, 2)
Alex make love
love make alex
love
love " \ + = make ----/== alex
补充示例1:
print(re.findall("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>")) #[‘h1‘]
print(re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>").group()) #<h1>hello</h1>
print(re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>","<h1>hello</h1>").groupdict()) #<h1>hello</h1>
print(re.search(r"<(\w+)>\w+</(\w+)>","<h1>hello</h1>").group())
print(re.search(r"<(\w+)>\w+</\1>","<h1>hello</h1>").group())
运行结果:
[‘h1‘]
<h1>hello</h1>
{‘tag_name‘: ‘h1‘}
<h1>hello</h1>
<h1>hello</h1>
补充示例2:
print(re.findall(r‘-?\d+\.?\d*‘,"1-12*(60+(-40.35/5)-(-4*3))")) #找出所有数字[‘1‘, ‘-12‘, ‘60‘, ‘-40.35‘, ‘5‘, ‘-4‘, ‘3‘]
#使用|,先匹配的先生效,|左边是匹配小数,而findall最终结果是查看分组,所有即使匹配成功小数也不会存入结果
#而不是小数时,就去匹配(-?\d+),匹配到的自然就是,非小数的数,在此处即整数
print(re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")) #找出所有整数[‘1‘, ‘-2‘, ‘60‘, ‘‘, ‘5‘, ‘-4‘, ‘3‘]
运行结果:
[‘1‘, ‘-12‘, ‘60‘, ‘-40.35‘, ‘5‘, ‘-4‘, ‘3‘]
[‘1‘, ‘-2‘, ‘60‘, ‘‘, ‘5‘, ‘-4‘, ‘3‘]
总结:
尽量精简,详细的如下
尽量使用泛匹配模式.*
尽量使用非贪婪模式:.*?
使用括号得到匹配目标:用group(n)去取得结果
有换行符就用re.S:修改模式
几个常见正则例子:
匹配手机号:
phone_str = "hey my name is alex, and my phone number is 13651054607, please call me if you are pretty!"
phone_str2 = "hey my name is alex, and my phone number is 18651054604, please call me if you are pretty!"
m = re.search("(1)([358]\d{9})",phone_str2)
if m:
print(m.group())
匹配IPv4
ip_addr = "inet 192.168.60.223 netmask 0xffffff00 broadcast 192.168.60.255"
m = re.search("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", ip_addr)
print(m.group())
分组匹配地址
contactInfo = ‘Oldboy School, Beijing Changping Shahe: 010-8343245‘
match = re.search(r‘(\w+), (\w+): (\S+)‘, contactInfo) #分组
"""
>>> match.group(1)
‘Doe‘
>>> match.group(2)
‘John‘
>>> match.group(3)
‘555-1212‘
"""
match = re.search(r‘(?P<last>\w+), (?P<first>\w+): (?P<phone>\S+)‘, contactInfo)
"""
>>> match.group(‘last‘)
‘Doe‘
>>> match.group(‘first‘)
‘John‘
>>> match.group(‘phone‘)
‘555-1212‘
"""
匹配email
email = "[email protected] http://www.oldboyedu.com"
m = re.search(r"[0-9.a-z]{0,26}@[0-9.a-z]{0,20}.[0-9a-z]{0,8}", email)
print(m.group())