python 正则表达式
应用场景
-
特定规律字符串的查找替换切割等
-
邮箱格式、url等格式的验证
-
爬虫项目,提取特定的有效内容
-
很多应用的配置文件
使用原则
-
只要能够通过字符串等相关函数能够解决的,就不要使用正则
-
正则的执行效率比较低,会降低代码的可读性
-
世界上最难读懂的三样东西:医生的处方、道士的神符、码农的正则
-
提醒:正则是用来写的,不是用来读的,不要试着阅读别人的正则;不懂功能时必要读正则。
基本使用
-
说明:正则是通过re模块提供支持的
-
相关函数:
-
match:从开头进行匹配,找到就立即返回正则结果对象,没有就返回None
-
search:匹配全部内容,任意位置,只要找到,立即返回正则结果对象,没有返回None
# python依赖次模块完成正则功能 import re # 从开头进行匹配,找到一个立即返回正则结果对象,没有返回None m = re.match('abc', 'abchelloabc') # 匹配全部内容,任意位置,只要找到,立即返回正则结果对象,没有返回None m = re.search('abc', 'helloabcshsjsldj') if m: print('ok') # 获取匹配内容 print(m.group()) # 获取匹配位置 print(m.span())
-
findall:匹配所有内容,返回匹配结果组成的列表,没有的返回一个空列表
# 匹配所有内容,返回匹配结果组成的列表,没有返回None f = re.findall('abc', 'abcsdisuoiabcsjdklsjabc') if f: print(f)
-
compile:根据字符串生成正则表达式的对象,用于特定正则匹配,通过match、search、findall匹配
# 根据字符串生成正则表达式的对象,用于正则匹配 c = re.compile('abc') # 然后进行特定正则匹配 # m = c.match('abcdefghijklmn') m = c.search('abcdefghijklmn') if m: print(m) print(c.findall('abcueywiabcsjdkaabc'))
将re模块中的match、search、findall方法的处理过程分为了两步完成。
-
正则规则
-
单个字符
普通字符:就是一对一的完全匹配
[]:中间的任意一个字符
[a-z]:表示a到z的任意字符
[0-9]:表示0到9的任意字符
[^abc]:除abc之外的字符
. :匹配'\n'以外的任意字符
\d:所有的数字字符,等价于[0-9]
\D:所有的非数字字符,等价于[^0-9]
\w:所有的数字、字母、中文、下划线等 (就是字的意思)
\W:\w之外的所有字符
\s:所有的空白字符,如:空格、\t、\n、\r
\S:\s之外的所有字符
\b:词边界,如:开头、结尾、标点、空格等
\B:非词边界 -
次数控制
*:前面的字符可以是任意次
+:前面的字符至少出现一次
?:至多一次,0次或1次
{m}:匹配固定的m次
{m,}:至少m次
{m,n}:m到n次正则的匹配默认是贪婪的
-
边界限定
-
^:以指定内容开头
-
$:以指定内容结尾
import re # 以指定内容开头 # c = re.compile(r'^abc') # 以指定内容结尾 # c = re.compile(r'abc$') # 同时限制开头和结尾 c = re.compile(r'^abc$') s = c.search('abc') if s: print('ok') print(s.group())
-
-
分组匹配
-
|:表示或,具有最低的优先级
-
():用于表示一个整体,可以确定优先级
import re # | 表示或,具有最低的优先级 # () 用于表示一个整体,可以确定优先级 c = re.compile(r'a(hello|world)d') s = c.search('aworldd') if s: print('ok') print(s.group())
()还有分组匹配的作用,下次再讲。
-
练习:
-
若匹配有特殊正则含义的字符怎么办,如:\d
-
友情提示:转义问题(python中转义一次、正则解析转义一次)
-
import re c=re.compile(r'\\d') s=c.search('\d1sfcef\d') if s: print('ok') print(s.group())
-
验证一个字符串是否是正确的邮箱格式
-
import re c=re.compile(r'\w+@(\w+\.)+\w+') string='lijie@163.com' s=c.search(string) if s: print('ok') print(s.group())
-
验证一个字符串是否是正确的url格式
-
import re c=re.compile(r'(http|http)://(\w+\.){2,}\w+(:\d+)?(\?(&?\w+=\w+)+)?') s=c.match('http://www.baidu.com:80?name=xiaoming&age=10') if s: print('ok') print(s.group())
思路
-
以功能为导向
-
写出符合规则的若干字符串
-
写一点测一点,不断的调整
-
最终完成功能
转义字符
-
在匹配所有正则中有特殊含义的字符时,都需要转义。
-
正则字符串需要被处理两次,python中处理,正则解析时处理一次。
-
通常在写正则字符串时,前面都加一个'r',表示原始字符,让所有的字符失去意义。
-
在匹配有如:'\'的字符时,前面再添加一个'\'就可以了,如果没有添加'r',通常要写好几个。
贪婪匹配
-
贪婪:最大限度的匹配,正则的匹配默认是贪婪的。
-
非贪婪:只要满足匹配条件,能少匹配就少匹配,通常使用'?'取消贪婪
-
示例:
import re # c = re.compile(r'a.*?c') c = re.compile(r'a.+?c') s = c.search('abcjsdhfkdkc') if s: print('ok') print(s.group())
分组匹配
-
():可以表示作为一个整体,也可以用来分组匹配
-
示例:
import re c = re.compile(r'(\d+)([a-z]+)(\d+)') s = c.search('sda123ksdak456sdk') if s: print('ok') print(s.group()) # 等价于上式 print(s.group(0)) # 里面的数字表示第几个分组,也就是第几个小括号匹配的结果 print(s.group(1)) print(s.group(2)) print(s.group(3))
-
示例:
import re # 正则中的\1:表示前面第一个小阔号匹配的结果 # c = re.compile(r'<([a-z]+)><([a-z]+)>\w*</\2></\1>') # c = re.compile(r'<(?P<hello>[a-z]+)><(?P<world>[a-z]+)>\w*</\2></\1>') # 可以给指定的分组起个名字 c = re.compile(r'<(?P<hello>[a-z]+)><(?P<world>[a-z]+)>\w*</(?P=world)></(?P=hello)>') s = c.search('xxx<div><a>百度一下</a></div>yyy') if s: print('ok') print(s) print(s.group())
匹配模式
-
说明:可以对匹配的模式作出整体的修饰处理,如:忽略大小写等
-
示例:
import re # 忽略大小写 # c = re.compile(r'hello', re.I) # 多行匹配 # c = re.compile(r'^hello', re.M) # 作为单行处理 或 让 . 匹配 '\n' c = re.compile(r'<div>.*?</div>', re.S) string = '<div>hello</div>' string = '''<div> hello </div>''' s = c.search(string) if s: print('ok') print(s.group())
字符串切割
- 说明:某些情况下,无法通过字符串函数进行切割,可以使用正则的方式处理,如:按照数字切割
- 示例:
```python
import re c = re.compile(r'\d') string = '正则1其实不难2但是学完发现自己写不出来3是这样吧' # 按照正则进行切割,可以指定切割次数,默认不限制,等价于:re.split() ret = c.split(string, maxsplit=1) print(ret) print(type(ret))
字符串替换
-
说明:简单的替换可以自己处理,要按照正则规律进行替换就需要使用专门的函数
示例:
import re ''' # 简单的正则替换,不需要人为干预替换过程 c = re.compile(r'\d') string = 'daeuo1iwuabca3sdalksjabcd2askabc' ret = c.sub('yyy', string) print(ret) ''' def deal(s): # 参数是每一个匹配整个的正则结果对象 ret = int(s.group()) # 会使用该函数返回的字符串替换对应的匹配 return str(ret * 2)
可以干预正则替换的过程,传递一个函数
ret = re.sub(r'\d', deal, 'sdh1askj2dlk3saj') print(ret)