Python之正则表达式(re模块)
正则表达式 (re模块)—— 字符串匹配的
学习使用re模块来操作正则表达式。
首先通过例子来看一下使用正则的优越性。
1.普通方法实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
while True: phone_number = input('please input your phone number : ') if len(phone_number) == 11 \ and phone_number.isdigit()\ and (phone_number.startswith('13') \ or phone_number.startswith('14') \ or phone_number.startswith('15') \ or phone_number.startswith('18')): print('是合法的手机号码') else: print('不是合法的手机号码')
2.正则实现
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
import re #导入正则模块 phone_number = input('please input your phone number : ')#初始输入 if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):#正则匹配验证判断 print('是合法的手机号码') else: print('不是合法的手机号码')
通过上面两种方法可以明显看出正则所具有的优越性。
为了使特殊字符显示本来的样子,这里通过在特殊字符串前加'r'来实现。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
print(r'\\n') print(r'\n')
1.1 python正则表达式中的元字符
python中特殊字符有 \.^$?+*{}[]()|
1.1.1 字符类速记
^ | 在起始处匹配,也可以在带MULTILINE标记的每个换行符后匹配 |
- | 表示一个字符范围,如果作为字符类中的第一个字符,就表示一个字面意义上的连字符 |
. | 可以匹配除换行符之外的任意字符,或带re.DOTALL标记的任意字符,或匹配字符类内部的字面意义的字符 |
\d | 匹配一个Unicode数字,或带re.ASCII标记的[0-9] |
\D | 匹配一个Unicode非数字,或带re.ASCII标记的[^0-9] |
\s | 匹配Unicode空白,或带re.ASCII标记的[\t\n\r\f\v] |
\S | 匹配Unicode非空白,或带re.ASCII标记的[^\t\n\r\f\v] |
\w | 匹配一个Unicode单词字符,或带re.ASCII标记的[a-zA-Z0-9_] |
\W | 匹配一个Unicode非单词字符,或带re.ASCII标记的[^a-zA-Z0-9_] |
\b | 在单词边界匹配,受re.ASCII影响,如果在字符内部则是backspace的转义字符 |
\B | 在非单词边界匹配,受re.ASCII影响 |
$ | 在结尾处匹配,也可以在带MULTILINE标记的每个换行符前匹配 |
* | 重复匹配零次或者更多次(贪婪模式).贪婪模式:尽可能多的匹配遇到的重复。 |
(?:……) | 该子组匹配的字符串无法从后边获取 |
+ | 重复匹配1次或者更多次(贪婪模式) |
? | 重复匹配0次或者1次(贪婪模式). |
\\ | 转义特殊字符或表示特殊序列 |
[] | 表示一组字符,如果以"^"为第一个字符,表示一组字符的互补集 |
[^] | 除了字符组内的其他都匹配 |
| | A|B, 选择分支,或者匹配A或者匹配B |
(...) | 匹配一个分组,将括号中的内容当作一个整体来对待 |
(?P<name>...) | 组匹配的子字符串,可以能一个名称访问. |
(?P=name) | 对指定的组反向的引用,以前面的以name为名称的组匹配的文本为分组内容,匹配后面的内容 |
(?=...) | 当该表达式匹配成功的时候,它的前面的表达式才会匹配 |
(?!...) | 当该表达式不匹配的时候,它的前面的表达式都会匹配成功 |
(?<=...) | 匹配以...开始的后面部分的字串,只能是固定的长度,也就是一个明确的表达式.说明:该模式不能于一个字符串的开始 |
(?<!...) | 匹配不是以...开始的后面部分的字串.只能是固定的长度 |
(?(id/name)yes|no) | (?(id/name)yes|no) 如果前面以id/name表示的正则匹配,则利用yes处的正则表达式匹配后面的字符串,否则用no处的匹配 |
1.1.2 量词
格式{m,n},m与n分别表示使用该量词的表达必须匹配的最少次数与最多次数。如果只给定一个数字则同时表示最小值最大值
量词速记形式:
e{m} | 准确匹配表达式e的m次出现 |
e{m,} | 贪婪地匹配表达式e至少m次出现 |
e{m,}? | 非贪婪地匹配表达式e至少m次出现 |
e{,n} | 最多n次出现 |
e{,n}? | 贪婪 |
e? | e{0,1} |
e?? | e{0,1}? |
e+ | e{1,} |
e+? | e{1,}? |
e* | e{0,} |
e*? | e{0,}? |
.*?abc | 一直取遇到abc就停 |
[] | 匹配[]内的任意一个内容 |
() | 将()的内容作为一个整体来进行匹配 |
贪婪表示会尽可以多的匹配符合条件的字符,非贪婪则为尽可以少的匹配。
1.1.3 正则表达式模块标记
re.A 或 re.ASCII | |
re.I 或 re.IGNORECASE | 忽略大小写 |
re.M 或 re.MULTILINE | 使^在起始处并在每个换行符后匹配,使$在结尾处但在每个换行符之前匹配 |
re.S 或 re.DOTALL | 使.匹配每个字符,包括换行符 |
re.X 或 re.VERBOSE | 使空白与注释包含在匹配中 |
1.2 RE之findall方法
返回所有满足匹配条件的结果,放在列表里。
import re ret = re.findall('[a-z]+', 'eric lucifer yuan')#匹配属于a-z的多个字符 print(ret)
1.3 RE之search方法
从前往后,找到一个就返回,返回的变量需要调用group才能拿到结果。如果没有找到,那么返回None,调用group会报错。
#找到第一个符合要求的就输出 import re ret = re.search('a', 'eric egon yuan') if ret: print(ret.group())
1.4 RE之match方法
1.match是从头开始匹配,如果正则规则从头开始可以匹配上,就返回一个变量。
2.匹配的内容需要用group才能显示。如果没匹配上,就返回None,调用group会报错。
import re ret = re.match('[a-z]+', 'eva egon yuan') if ret: print(ret.group())
1.5 RE之split方法
import re ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割 print(ret) # ['', '', 'cd']
1.6 RE之sub与subn方法
import re ret = re.sub('\d', 'H', 'eva3egon4yuan4',1) #先进行数字匹配,在将数字替换成'H',参数1表示只替换1个 print(ret) #evaHegon4yuan4 import re ret = re.subn('\d', 'H', 'eva3egon4yuan4') #将数字替换成'H',返回元组(替换的结果,替换了多少次) print(ret)
1.7 RE之compile方法
此法可用于多次匹配同一种类型的结果时使用,这样只编译了一次,加快了程序执行速度。
import re obj = re.compile('\d{3}')#匹配数字,重复次数:3次 #将正则表达式编译成为一个正则表达式对象,规则要匹配的是3个数字 ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串 print(ret.group()) ret = obj.search('abcashgjgsdghkash456eeee3wr2') #正则表达式对象调用search,参数为待匹配的字符串 print(ret.group()) #结果 : 123
1.8 RE之finditer方法
filter就是将符合正则表达式的存入迭代器,读取时可以通过next(ret).group()进行一个一个读,也可以通过循环一次读完。
import re ret = re.finditer('\d', 'ds3sy4784a') #finditer返回一个存放匹配结果的迭代器 print(ret) # <callable_iterator object at 0x10195f940> print(next(ret).group()) #查看第一个结果 print(next(ret).group()) #查看第二个结果 print([i.group() for i in ret]) #查看剩余的左右结果 for i in ret: print(i.group())
1.9 复杂正则的使用
1.9.1 findall
import re ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['oldboy']这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可 import re ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') print(ret) # ['www.oldboy.com']
1.9.2 search
import re ret = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199912122277') print(ret.group()) print(ret.group(1)) print(ret.group(2))
1.9.3 split
import re ret=re.split("\d+","eva3egon4yuan") print(ret) #结果 : ['eva', 'egon', 'yuan'] import re ret=re.split("(\d+)","eva3egon4yuan") print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']
1.9.4 爬虫实例
import re from urllib.request import urlopen def getPage(url): response = urlopen(url) return response.read().decode('utf-8') def parsePage(s): ret = re.findall( '<div class="item">.*?<div class="pic">.*?<em .*?>(?P<id>\d+).*?<span class="title">(?P<title>.*?)</span>' '.*?<span class="rating_num" .*?>(?P<rating_num>.*?)</span>.*?<span>(?P<comment_num>.*?)评价</span>',s,re.S) return ret def main(num): url = 'https://movie.douban.com/top250?start=%s&filter=' % num response_html = getPage(url) ret = parsePage(response_html) print(ret) count = 0 for i in range(10): # 10页 main(count) count += 25
步骤:
1> url从网页上把代码搞下来
2> bytes decode ——> utf-8 网页内容就是我的待匹配字符串
3> ret = re.findall(正则,带匹配的字符串) #ret是所有匹配到的内容组成的列表