一、简介
最近开始学python3了,看到正则表达式这一块,发现以前做Android开发时都很少接触这一块,所以想做个总结,网上的学习资料挺多的,我自己算是做个学习笔记吧,学习一下正则表达式基础的东西,以及正则表达式在python中的使用 。
二、Python3 正则表达式
Python 语言中内置了re 模块来提供正则表达式的一些操作,所以我们可以直接调用来实现正则表达式的匹配。
在了解python3中的正则表达式之前,需要先了解一下正则表达式的一些基本概念和用法;
什么是正则表达式:
这里套用一下百度百科的解释,正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。
上面提到的“规则字符”,就是用来书写正则表达式的,而且正则表达式也是以字符串的形式来表示的,以下列出正则表达式中部分普通字符和特殊字符:
- 特殊字符:
'.'
匹配除 "\n" (换行符)之外的任何单个字符,如:'py.'
可以匹配'pyc'
、'pyo'
、'py!'
;'^'
匹配字符串的开头;'$'
匹配字符串的末尾;'*'
匹配0个或多个的表达式;'+'
匹配1个或多个的表达式。'?'
匹配0个或1个的表达式;'*?,+?,??'
前三个特殊字符的非贪婪版本;'{m,n}'
匹配 n 到 m 次前面的字符(表达式),贪婪方式, 如:\d{3,8}
表示3-8个数字,匹配'1234567'
;'{m}'
匹配前一个字符(表达式)m次,贪婪方式,如\d{3}
表示3个数字,匹配'110'
;'{m,n}?'
匹配前面两个非贪婪方式;'\'
转义特殊字符;'[]'
表示一组字符;'|'
或字符,如: 'A|B' ,匹配A或者B;'(...)'
匹配括号内的表达式,也可以表示一个组,之后可以在字符串中检索或匹配内容;'(?aiLmsux) '
设置正则表达式可选的7中标记A、I、L、M、S、U或X,见下面的flags;'(?:...) '
类似 (...), 但是不表示一个组;'(?P<name>...)'
匹配一个组,并且给匹配的子字符串一个别名。
- 普通字符:
'\A'
匹配字符串开始;'\B'
匹配非单词边界。'er\B'
能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er';'\b'
匹配一个单词边界,也就是指单词和空格间的位置。例如,'er\b'
可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er'。'\d'
匹配任意数字,等价于 [0-9]。如:'00\d'
可以匹配'007'
,但无法匹配'00A'
;'\D'
匹配任意非数字;'\w'
匹配数字字母下划线,如:'\w\w\d'
可以匹配'py3'
;'\W'
匹配非数字字母下划线。正好和'\w'
相反;'\s'
匹配任意空白字符,等价于 [\t\n\r\f]。'\S'
匹配任意非空字符,等价于[^\s]
;'\Z'
匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串;'\z'
匹配字符串结束
- 特殊字符:
Python re模块中的一些函数使用的标志(flags)可选参数:
re.I 使匹配对大小写不敏感 re.L 做本地化识别(locale-aware)匹配 re.M 多行匹配,影响 ^ 和 $ re.S 使 . 匹配包括换行在内的所有字符 re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. re.A 使 \w \W \b \B \s \S 只匹配 ASCII 字符,而不是 Unicode 字符
三、re模块中常用功能函数
re.match()
尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。
# 完整函数: ''' @param pattern 匹配的正则表达式 @param string 要匹配的字符串 @param flags 标志位,用于控制正则表达式的匹配方式, 见上述(flags)可选参数。 ''' re.match(pattern, string, flags=0)
示例:
import re obj = re.match(r'^\d{3}\-\d{3,8}$', '010-12456') if obj is None: print('sorry,没找到与之匹配的结果') else: print('yes,找到了与之匹配的结果') # 打印结果:yes,找到了与之匹配的结果
re.search()
查找字符串中可以匹配成功的子串并返回匹配对象,如果没有找到匹配的对象,则返回None。
# 完整函数 ''' @param pattern 匹配的正则表达式 @param string 要匹配的字符串 @param flags 标志位,用于控制正则表达式的匹配方式, 见上述(flags)可选参数。 ''' match(pattern, string, flags=0)
示例:
import re print(re.search('www', 'www.baidu.com').group()) print(re.search('com', 'www.baidu.com').group()) # 打印结果 www com
re.match与re.search的区别:
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
- match和search一旦匹配成功,就是一个match object对象,而match object对象有以下方法
- group() 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组;
- start() 返回匹配开始的位置;
- end() 返回匹配结束的位置;
- span() 返回一个元组包含匹配 (开始,结束) 的位置;
- groups() 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
示例1:
# 从字符串开头匹配,匹配到返回match的对象,匹配不到返回None re_match = re.match("c", "abcde"); if (re_match): print("re_match:" + re_match.group()); else: print("re_match:None"); # 扫描整个字符串返回第一个匹配到的元素并结束,匹配不到返回None re_search = re.search("c", "abcde"); if (re_search): print("re_search:" + re_search.group()); #打印结果: re_match:None re_search:c
示例2:
import re # match m = re.match(r'^(\d{3})-(\d{3,8})', '012-10086') print(m) print(m.group(0,1,2)) # 返回元组 print(m.groups()) #打印结果: (0, 9) 0 9 ('012-10086', '012', '10086') ('012', '10086') # search m = re.search(r'(abc)', 'pppabc123456abc') print(m.span()) print(m.start()) print(m.end()) print(m.group(0,1)) # 返回元组 print(m.groups()) # 打印结果: (3, 6) 3 6 ('abc', 'abc') ('abc',)
re.split()
按照能够匹配的子串将string分割后返回列表。
# 完整函数 ''' @param pattern 匹配的正则表达式 @param string 要匹配的字符串 @param maxsplit 分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。 @param flags 标志位,用于控制正则表达式的匹配方式, 见上述(flags)可选参数。 ''' split(pattern, string, maxsplit=0, flags=0)
示例:
import re print(re.split(r'\s+', 'a b cc dd ee rr')) # 可以识别多余的空格 print(re.split(r'[\s\,]+','a,b,c,d,e f g,,,fd d')) # 无论多少个空格 ,号 ;号都可以识别 # 打印结果 ['a', 'b', 'cc', 'dd', 'ee', 'rr'] ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'fd', 'd']
re.compile()
此函数会编译正则表达式,并将编译后的正则表达式和字符串匹配。
如果一个正则表达式要重复使用成百上千次,出于效率的考虑,我们可以预编译该正则表达式,接下来重复使用时就不需要再编译,直接去匹配就好了
# 完整函数 ''' @param pattern 匹配的正则表达式 @param flags 标志位,用于控制正则表达式的匹配方式, 见上述(flags)可选参数。 ''' re.compile(pattern, flags=0)
示例:
import re re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$') print(re_telephone.match('010-12345').groups()) print(re_telephone.match('010-8086').groups()) #打印数据 ('010', '12345') ('010', '8086')
re.findall()
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。
注意: match 和 search 是匹配一次 findall 匹配所有。
# 完整函数 ''' @param string 待匹配的字符串。 @param pos 可选参数,指定字符串的起始位置,默认为 0。 @param endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。 ''' re.findall(string, pos, endpos)
示例:
import re pattern = re.compile(r'\d+') # 查找数字 result1 = pattern.findall('shanghai 123 beijing 456') result2 = pattern.findall('aaa333bbb555ccc666', 0, 18) print(result1) print(result2) # 打印结果 ['123', '456'] ['333', '555', '666']
re.finditer()
和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。
# 完整函数 ''' @param pattern 匹配的正则表达式 @param string 要匹配的字符串。 @param flags 标志位,用于控制正则表达式的匹配方式, 见上述(flags)可选参数。 ''' re.finditer(pattern, string, flags=0)
示例:
import re it = re.finditer(r"\d+", "12a32bc43jf3") for match in it: print(match.group()) # 打印结果: 12 32 43 3
re.sub()
使用正则表达式替换string中每一个匹配的子串后返回替换后的字符串。
# 完整函数 ''' @param pattern 匹配的正则表达式字符串形式。 @param repl 替换的字符串,也可为一个函数 @param string 要被查找替换的原始字符串 @param count 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。 @param flags 标志位,用于控制正则表达式的匹配方式, 见上述(flags)可选参数。 ''' re.sub(pattern, repl, string, count=0, flags=0)
示例:
import re phone = "2004-959-559 # 这是一个电话号码" print(re.sub(r'#.*$', '', phone)) # 删除了注释之后的内容 print(re.sub(r'\D', '', phone)) # 删除非数字的内容 # 将匹配的数字乘于 2 def double(matched): value = int(matched.group('value')) return str(value * 2) s = 'A23G4HFD567' print(re.sub('(?P<value>\d+)', double, s)) # 匹配一个组,并且给匹配的子字符串一个别名 # 打印结果: 2004-959-559 2004959559 A46G8HFD1134
re.subn()
返回一个元组包含替换后的字符串和正则表达式匹配的次数
# 完整函数 ''' @param pattern 匹配的正则表达式字符串形式。 @param repl 替换的字符串,也可为一个函数 @param string 要被查找替换的原始字符串 @param count 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。 @param flags 标志位,用于控制正则表达式的匹配方式, 见上述(flags)可选参数。 ''' re.subn(pattern, repl, string, count=0, flags=0)
示例:
import re print(re.subn('[1-2]', 'A', '123456abcdef')) print(re.subn("g.t", "have", 'I get A, I got B ,I gut C')) # 打印结果: ('AA3456abcdef', 2) ('I have A, I have B ,I have C', 3)
贪婪匹配
正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符 例如:
import re print(re.match(r'^(\d+)(0*)$', '108600').groups()) # \d+采用贪婪匹配 # 解决方式: *?,+?,??,{m,n}? 前面的*,+,?等都是贪婪匹配,后面加?号使其变成非贪婪匹配 print(re.match(r'^(\d+?)(0*)$', '108600').groups()) # \d+?采用非贪婪匹配 # 打印结果: ('108600', '') # 可以看到0后面的内容全部被第一组匹配走了,第二组什么都没有匹配到 ('1086', '00') # 通过非贪婪匹配方式,两组都匹配到了内容
四、小结
以上只是正则表达式冰山一角的内容,这篇文章也只能算是给自己学习正则表达式提供一些小思路,也是学习之路。当然这里面最重要的其实是那些示例,这里参考了挺多的文章,有的直接拷贝过来了,以下会列出这些大神的博客链接,感谢他们的分享!
五、参考资料
http://www.runoob.com/python3/python3-reg-expressions.html
https://www.cnblogs.com/tina-python/p/5508402.html
https://www.cnblogs.com/bdhk/p/7447616.html