正则表达式
定义+特点
- 什么是正则表达式:一套用于匹配字符串的规则
- 正则表达式测试网站(http://tool.chinaz.com/regex/)
- 能做什么:
- 用户输入内容的时候,我们可以提前检测输入是否符合规则(如登录)
- 能够提升程序的效率以及减轻服务器的压力
- 能够高效快速地从一大段文字中找到符合规则的内容
- 从大文件中找到符合规则的字符串(如日志分析/爬虫)
- 用户输入内容的时候,我们可以提前检测输入是否符合规则(如登录)
- 正则规则
- 用于从获取到的字符串提取符合定义规则的字符串内容
元字符
-
在正则表达式中能帮助我们表示匹配的内容的符号就是正则中的元字符
-
[ ] : 字符组(描述的是一个位置上能出现的可能性) 与[ ^ ]:非字符组
- [abc]一个字符组只表示一个字符的位置:匹配a/b/c
- [0 - 9] 根据ascii的顺序进行范围比对的
- [a -z] [A-Z] [a-zA-Z] [0-9a-zA-Z]
- [_\t\n] 匹配到(空格,Tab和回车)
- [ ^/d ]表示匹配所有非数字
\d: 表示匹配的所有数字(0-9) (digit)
\w: 表示匹配的是数字字母下划线 (word)
\s: 表示匹配表示空白
_\t\n: 匹配到(空格,Tab和回车)
\D: 表示只要不是数字都可以匹配
\W: 表示只要不是数字字母下划线就可以匹配
\S: 表示只要不是空白就可以匹配
[\d\D] [\s\D] [\w\W]: 表示匹配所有
^: 匹配字符串的开始
$: 匹配字符串的结尾
. :表示匹配出换行符外的所有
|: 表示或,(ad|bc)匹配ad或bc,但如果ad匹配成功了就不会去匹配bc,所以如果两个规则有重叠部分,总是将长的放前面
( ): 约束,如www.(taobao|baidu|jingdong).com
-
量词
- 量词
-
{n}: 表示重复n次
- {n,} : 表示重复最少n次
- {n,m} : 表示重复最少n次,最多m次
- ?: 表示重复0次或一次
- +: 表示重复1次或多次
- *: 表示重复0次或多次
- \d+表示所有整数 \d+\ .\d+ 表示所有小数
- \d+\ .?\d+表示整数或小数(有缺陷)
- \d+(\ .\d+)? 表示完整的整数和小数
贪婪匹配与非贪婪匹配
-
贪婪匹配(回溯算法)
- 在量词允许的范围下尽可能匹配多的内容
- .*x 表示匹配任意字符 任意多次,遇到最后的x才停下来
非贪婪(惰性)匹配----> (量词+?)
-
在量词允许的范围内尽可能少的匹配内容
- .*?x 表示匹配任意字符 任意多次,遇到第一个x就停下来
转义符
-
转义符
- 原本有特殊意义的字符,到了表达它本身的意义的时候需要转义符 **\ **
- \ \t \ \n \ . \ - \ ? **\ + ** **\ * ** \ ( \ )
- 有一些有特殊意义的内容,放在字符组 **[ ] **中,会取消它的特殊意义
- [().*?+] 所有的内容在字符组中会取消它的特殊意义
- [a\ -c] -在字符组中表示范围,如果不希望它表示范围,就需要转义,或者放在字符组最前面或者最后面
- 原本有特殊意义的字符,到了表达它本身的意义的时候需要转义符 **\ **
-
正则实例
- ^([1-9] \d{16}[\dx]|[1-9]\d{14})$ : 匹配17位身份证
re模块
re.findall
-
re.findall ('正则表达式' , '内容字符串')
- 可通过分组 ( ) 来设置分组优先,从而只显示分组中的内容
- 为什么用到分组:比如我们要查找的内容在一个非常复杂的环境中,而这个环境没有什么明显的特征,甚至会和其他混乱的信息掺杂在一起,这时候我们就需要设置分组来筛选我们所需要的数据
- 可通过 ( ?: ) 来取消分组优先
- 分组命名的引用 (?P < name > 正则表达式)
- 使用ret.group('name')来获取数据
- \1在正则表达式里是表示第一个分组
- 可以用r" "去取消原本转义
ret=re.search(r'<(\w+)>(?P<name>.*?)</\1>','<h1>yuhu788</h1> <h2>uyu7678</\h2>')
print(ret.group('name'))import re
ret1=re.findall('1\d\d','167jjh767yhg17926')
print(ret1) #['167', '179']
ret2=re.findall('1(?:\d)(\d)','167jjh767yhg17926') #设置分组优先
print(ret2) #['7', '9']- 什么是爬虫
- 通过代码ret=request.get('网页')去获取一个网页的源码
- 通过re模块筛选从网页上获取的源码内容
- 可通过分组 ( ) 来设置分组优先,从而只显示分组中的内容
re.search
-
re.search('正则表达式' , '内容字符串')
- 按照完整的正则进行匹配,只会显示匹配到第一个的字符串内容
-
设置分组优先对re.search没用
- 结果通过.group( )获取
import re
ret1=re.search('1\d\d','167jjh767yhg17926')
print(ret3.group()) #167
ret2=re.search('1(\d)\d','167jjh767yhg17926')
print(ret4.group()) #167
re.match
-
re.match('正则表达式' , '内容字符串')
- 按照完整的正则进行匹配,只会显示匹配到第一个的字符串内容
- 结果通过.group( )获取
-
与re.search对比,re.match在正则前默认加上了元字符^
import re
#第一种,会报错
ret1=re.match('1\d\d','467jjh767yhg17926')
print(ret1.group()) #AttributeError: 'NoneType' object has no attribute 'group'
#第二种,匹配成功,正常运行
ret2=re.match('1\d\d','167jjh767yhg17926')
print(ret2.group()) #167
re.compile
-
re.compile('正则表达式' )
- 从时间上节省,当连续多次使用同一个正则表达式时,可以使用re.compile
import re
res=re.compile('\d+')
ret=res.findall('167jjh767yhg17926')
print(ret)
re.finditer
-
re.finditer('正则表达式' )
- 从空间上节省,生成一个iter迭代器
ret=re.finditer('\d+','167jjh767yhg17926')
for i in ret: #循环iteration
print(i.group()) #通过.group方法进行取值
#最终结果 #167
#767
#17926 -
可以既从时间上节省,也可以从空间上节省
import re
res=re.compile('\d+')
ret=res.finditer('167jjh767yhg17926')
for i in ret:
print(i.group()) #最终结果与上一个一致
re.split
-
re.split('正则表达式' , '内容字符串')
- 对内容字符串按正则进行切分
import re
ret=re.split('\d+','167jjh767yhg17926')
print(ret) #['', 'jjh', 'yhg', '']
re.sub
-
re.sub('正则表达式' , ' 要替换的字符串' , '内容字符串' , '替换的次数')
- 对内容字符串根据正则进行替换
import re
ret=re.sub('[a-zA-Z]+','yzh','167jjh767yhg17926',2)
print(ret) #167yzh767yzh17926
re.subn
-
re.subn('正则表达式' , ' 要替换的字符串' , '内容字符串' )
- 对内容字符串根据正则进行替换,返回一个元组,存放了最终结果以及替换次数
import re
ret=re.subn('[a-zA-Z]+','yzh','167jjh767yhg17926')
print(ret) #(167yzh767yzh17926,2)