首页 > 代码库 > 16-正则模块

16-正则模块

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

16-正则模块