一、 正则表达式概述
1. 作用:
1. 数据抓取,数据的清理 : 在网上抓取图片,清除网站中不雅的评论
2. 数据验证,比如验证邮箱的合法性,手机号码的合法性 ,11位数字
2. 特点:通用性,跨语言
主流语言都有正则表达式,而且表达式的规则都几乎相同的
二、 re模块
提示: 命令行: ctrl+e :到命令行的尾部
ctrl+A: 到命令行的头部
1. re模块的使用过程
a>import re
ret=re.match("itcast","itcast.cn")
ret
b> 匹配成功没
在命令行输入:ret
为空: 匹配失败
不为空: 匹配成功
c> 查看结果
ret.group()
2. 小结
1. re.match("正则表达式","要匹配的内容")
2. re.match ()是匹配以xxx开头的字符串
1. '.' : 表示匹配任意一个字符,除\n(换行)以外
问题: 看电影 输入电影名称: "速度与*情"
re.match("速度与.情","速度与基情")
问题: 看电影 选择电影名称: "速度与激情9" 1-9部都可以
re.match("速度与激情[123456789]","速度与激情1")
re.match("速度与激情[1-9]","速度与激情8")
re.match("速度与激情\s","速度与激情 ")
re.match("速度与激情\S","速度与激情u")
python2:单词字符不支持中文,python3支持中文,命名单词或者变量不建议用中文
re.match("\w","9")
re.match("\w","A")
re.match("\W","9")
re.match("\W","A")
re.match("\W","*")
1. {m} : 匹配前一个字符出现m次
问题:匹配手机号码, 11位数字
re.match("1\d{10}","13656789857")
re.match("1\d{10}","1365678985")
2. {m,n}: 匹配前一个字符出现m到n次
问题: 匹配广东电话号码的合法性 020-56745675 ,0755-12345678,0756-1234567
re.match("\d{3}-\d{8}","020-56745795")
re.match("\d{3,4}-\d{8}","0755-56745795")
re.match("\d{3,4}-\d{7,8}","0756-5674595")
3. ? : 前一个字符出现1次或者0次
问题: 匹配广东电话号码的合法性 02056745675 ,0755-12345678,07561234567
re.match("\d{3,4}-?\d{7,8}","07565674595")
re.match("\d{3,4}-?\d{7,8}","0756-5674595")
4. * : 匹配前一个字出现0次或者多次
问题: 把一个文本的内容全部匹配出来
content="""adslfjaldjgljagga\nasdiwerierydfgjr\n;sdfgrwjtrjg"""
re.match(".*",content,re.S)
re.match("a*","")
注意:
1. "." 不能匹配换行 \n
问题:空字符串匹配
re.match("a+","")
re.match("a+","aaaaaaaa")
五、匹配开头与结尾
1. ^ : 匹配以xxx开头的字符串
re.match("^itcast","itcast.cn")
re.match("itcast","itcast.cn") :match默认就是以itcast开头
re.match("^itcast","uitcast.cn")
re.match("itcast","uitcast.cn")
2. $ :匹配以xxx结尾的字符串
问题: 11位手机号码匹配
re.match("1\d{10}$","13654678906")
re.match("1\d{10}$","13654678906897")
六、案例:
1. 案例1: 判断变量名是否合法
names = ["age1", "1age", "AG0_", "_9age", "age_", "a9_G2#", "a#ffsd"]
需求(规则): 变量名合法: 字符由a-z,A-Z,0-9,_ 组成,但是首字符不能是数字
ret=re.match("[a-zA-Z_]\w*$",name)
参考代码:
import re
def main():
"""需求(规则): 变量名合法: 字符由a-z,A-Z,0-9,_ 组成,但是首字符不能是数字"""
names = ["age1", "1age", "AG0_", "_9age", "age_", "a9_G2#", "a#ffsd"]
# 迭代可迭代对象
for name in names:
ret=re.match("[a-zA-Z_]\w*$",name)
if ret:
print("变量名%s合法,匹配到的内容%s" %(name,ret.group()))
else:
print("变量名%s不合法"%name)
if __name__ == '__main__':
main()
2. 案例2:
匹配出163的邮箱地址,且@符号之前有4到20位单词字符,例如hello@163.com
email_list = ["lijun@163.com", "wang2_@qq.com", "lining@163.cn", "wang@163.com.cn","cheny@163ccom"]
ret = re.match("\w{4,20}@163\.com$",email)
参考代码:
import re
def main():
"""匹配出163的邮箱地址,且@符号之前有4到20位单词字符,例如hello@163.com"""
email_list = ["lijun@163.com", "wang2_@qq.com", "lining@163.cn", "wang@163.com.cn", "cheny@163ccom"]
# 遍历列表
for email in email_list:
# . 在正则表达式中表示匹配任意一个字符,但是当前需要一个 ".",通过"\" 转义符 转回原生(原来、本来的意义,初始的意义)的意义
ret = re.match("\w{4,20}@163\.com$",email)
if ret:
print("邮箱%s合法的,匹配的内容是:%s" % (email, ret.group()))
else:
print("邮箱%s不合法" % email)
if __name__ == '__main__':
main()
1. | :匹配左右任意一个表达式
问题: 同时匹配出 163和126邮箱的合法性(@符号之前有4到20位单词字符)
re.match("\w{4,20}@163\.com$|\w{4,20}@126\.com$","lijun@126.com")
re.match("\w{4,20}@163\.com$|\w{4,20}@126\.com$","lijun@163.com")
2. (ab) : 分组
问题1: 匹配多个邮箱地址
1. re.match("\w{4,20}@(163|126|qq)\.com$","lijun@126.com")
问题2:想取出合法邮箱特定的值,比如取163,126或者邮箱的前缀
In [166]: ret=re.match("(\w{4,20})@(163|126|qq)\.com$","lijun@qq.com")
In [167]: ret.group()
Out[167]: 'lijun@qq.com'
In [168]: ret.group(0)
Out[168]: 'lijun@qq.com'
In [169]: ret.group(1)
Out[169]: 'lijun'
In [170]: ret.group(2)
Out[170]: 'qq'
3. \num : 引用分组num匹配到的字符串
问题:需求(规则): html标签配对验证, 比如<h1>dsafagd</h1> ,标签必须配对
re.match("<(\w+)>.*</\\1>","<h1>你好dsafagd</h1>")
re.match("<(\w+)>.*</\\1>","<h1>你好dsafagd</h2>")
In [188]: print("\1") : "\1" : 转义成特殊的符号的,所以需要"\\1" ,转出原来的意义即反斜杠 \num
4. (?P<name>):分组起别名
5. (?P=name) : 引用别名为name分组匹配到的字符串
问题:问题4:需求:html标签配对验证, 比如<body><h1>dsafagd</h1></body>
1. re.match("<(\w+)><(\w+)>.*</\\2></\\1>","<body><h1>你好dsafagd</h1></body>")
2. re.match("<(\w+)><(\w+)>.*</\\2></\\1>","<body><h1>你好dsafagd</h1></bod>")
3. re.match("<(?P<p1>\w+)><(?P<p2>\w+)>.*</(?P=p2)></(?P=p1)>","<body><h1>你好dsafagd</h1></body>")
八. re模块的高级用法
a>re.search() :查找,搜索, 当搜索到匹配的内容,则返回
问题:匹配微信公众号文章阅读的次数 : "本文章阅读次数: 9998"
re.search("\d+","本文章阅读次数: 9998")
b>re.findall() : 找到所有匹配的数据,返回的是list
问题:找到本文的所有数字 "本文章阅读次数: 9998次,博客的阅读次数: 50"
ret=re.findall("\d+","本文章阅读次数: 9998次,博客的阅读次数: 50")
ret是列表,注意不要使用ret.group()
c> re.sub() : 替换操作
语法:re.sub("正则表达式","替换的内容","查找的字符串或者文本")
问题:将匹配到的阅读次数加1 "本文章阅读次数: 9998次,博客的阅读次数: 50"
In [226]: def add(temp):
...: strNum=temp.group()
...: num=int(strNum)+1
...: return str(num)
...:
...:
In [227]: ret=re.sub("\d+",add,"本文章阅读次数: 9998次,博客的阅读次数: 50")
In [228]: ret
Out[228]: '本文章阅读次数: 9999次,博客的阅读次数: 51'
d> split 根据匹配进行切割字符串,并返回一个列表
语法:re.split("分隔符正则表达式","要分割的文本")
问题: 分离字符串 "wang 18 广州 python"
In [230]: ret=re.split(" |:|-","wang 18-广州:python")
In [231]: ret
Out[231]: ['wang', '18', '广州', 'python']
In [232]: ret[0]
九、贪婪和非贪婪
Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪则相反,总是尝试匹配尽可能少的字符。
在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。
"*","?","+","{m,n}" : 特点,取字符的不确定性,存在贪婪与非贪婪,python默认是贪婪的,在"*","?","+","{m,n}"后面 加 ? ,把贪婪变为非贪婪
非贪婪
*: 0
?: 0
+: 1
{m,n} :m个
re.search("https://.+?\.jpg",img)
十、r的作用
Python中字符串前面加上 r 表示原生字符串
问题:与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰
re.match("<(\w+)><(\w+)>.*</\\2></\\1>","<body><h1>你好dsafagd</h1></bod>")
ret=re.match(r"<(\w+)><(\w+)>.*</\2></\1>","<body><h1>你好dsafagd</h1><
...: /body>")
1. 作用:
1. 数据抓取,数据的清理 : 在网上抓取图片,清除网站中不雅的评论
2. 数据验证,比如验证邮箱的合法性,手机号码的合法性 ,11位数字
2. 特点:通用性,跨语言
主流语言都有正则表达式,而且表达式的规则都几乎相同的
二、 re模块
提示: 命令行: ctrl+e :到命令行的尾部
ctrl+A: 到命令行的头部
1. re模块的使用过程
a>import re
ret=re.match("itcast","itcast.cn")
ret
b> 匹配成功没
在命令行输入:ret
为空: 匹配失败
不为空: 匹配成功
c> 查看结果
ret.group()
2. 小结
1. re.match("正则表达式","要匹配的内容")
2. re.match ()是匹配以xxx开头的字符串
三、 匹配单个字符
字符 | 功能 |
---|---|
. | 匹配任意1个字符(除了\n) |
[ ] | 匹配[ ]中列举的字符 |
\d | 匹配数字,即0-9 |
\D | 匹配非数字,即不是数字 |
\s | 匹配空白,即 空格,tab键 |
\S | 匹配非空白 |
\w | 匹配单词字符,即a-z、A-Z、0-9、_ |
\W | 匹配非单词字符 |
问题: 看电影 输入电影名称: "速度与*情"
re.match("速度与.情","速度与基情")
re.match("速度与.情","速度与\n情")
2.[] : 匹配[ ]中列举的字符问题: 看电影 选择电影名称: "速度与激情9" 1-9部都可以
re.match("速度与激情[123456789]","速度与激情1")
re.match("速度与激情[1-9]","速度与激情8")
re.match("速度与激情[1-35-9]","速度与激情5") : 除4以外的所有字符
3. \d: 表示任意一个数字 ,0-9 中的数字re.match("速度与激情\d","速度与激情9")
4. \D: 不是数字的任意一个字符re.match("速度与激情\D","速度与激情*")
5. \s : 匹配空格或者tab空格re.match("速度与激情\s","速度与激情 ")
re.match("速度与激情\s","速度与激情#")
6. \S : 除了空格tab键的空格以外的所有字符re.match("速度与激情\S","速度与激情u")
re.match("速度与激情\S","速度与激情 ")
7. \w : 匹配单词字符: 0-9,a-z,A-Z,_python2:单词字符不支持中文,python3支持中文,命名单词或者变量不建议用中文
re.match("\w","9")
re.match("\w","A")
re.match("\w","*")
8. \W : 匹配单词字符以外的所有字符re.match("\W","9")
re.match("\W","A")
re.match("\W","*")
四、 匹配多个字符
字符 | 功能 |
---|---|
* | 匹配前一个字符出现0次或者无限次,即可有可无 |
+ | 匹配前一个字符出现1次或者无限次,即至少有1次 |
? | 匹配前一个字符出现1次或者0次,即要么有1次,要么没有 |
{m} | 匹配前一个字符出现m次 |
{m,n} | 匹配前一个字符出现从m到n次 |
1. {m} : 匹配前一个字符出现m次
问题:匹配手机号码, 11位数字
re.match("1\d{10}","13656789857")
re.match("1\d{10}","1365678985")
2. {m,n}: 匹配前一个字符出现m到n次
问题: 匹配广东电话号码的合法性 020-56745675 ,0755-12345678,0756-1234567
re.match("\d{3}-\d{8}","020-56745795")
re.match("\d{3,4}-\d{8}","0755-56745795")
re.match("\d{3,4}-\d{7,8}","0756-5674595")
3. ? : 前一个字符出现1次或者0次
问题: 匹配广东电话号码的合法性 02056745675 ,0755-12345678,07561234567
re.match("\d{3,4}-?\d{7,8}","07565674595")
re.match("\d{3,4}-?\d{7,8}","0756-5674595")
4. * : 匹配前一个字出现0次或者多次
问题: 把一个文本的内容全部匹配出来
content="""adslfjaldjgljagga\nasdiwerierydfgjr\n;sdfgrwjtrjg"""
re.match(".*",content,re.S)
re.match("a*","")
注意:
1. "." 不能匹配换行 \n
2. re.S 表示多行匹配
5. + :匹配前一个字符出现1次或者无限次,即至少有1次问题:空字符串匹配
re.match("a+","")
re.match("a+","aaaaaaaa")
五、匹配开头与结尾
1. ^ : 匹配以xxx开头的字符串
re.match("^itcast","itcast.cn")
re.match("itcast","itcast.cn") :match默认就是以itcast开头
re.match("^itcast","uitcast.cn")
re.match("itcast","uitcast.cn")
2. $ :匹配以xxx结尾的字符串
问题: 11位手机号码匹配
re.match("1\d{10}$","13654678906")
re.match("1\d{10}$","13654678906897")
六、案例:
1. 案例1: 判断变量名是否合法
names = ["age1", "1age", "AG0_", "_9age", "age_", "a9_G2#", "a#ffsd"]
需求(规则): 变量名合法: 字符由a-z,A-Z,0-9,_ 组成,但是首字符不能是数字
ret=re.match("[a-zA-Z_]\w*$",name)
参考代码:
import re
def main():
"""需求(规则): 变量名合法: 字符由a-z,A-Z,0-9,_ 组成,但是首字符不能是数字"""
names = ["age1", "1age", "AG0_", "_9age", "age_", "a9_G2#", "a#ffsd"]
# 迭代可迭代对象
for name in names:
ret=re.match("[a-zA-Z_]\w*$",name)
if ret:
print("变量名%s合法,匹配到的内容%s" %(name,ret.group()))
else:
print("变量名%s不合法"%name)
if __name__ == '__main__':
main()
2. 案例2:
匹配出163的邮箱地址,且@符号之前有4到20位单词字符,例如hello@163.com
email_list = ["lijun@163.com", "wang2_@qq.com", "lining@163.cn", "wang@163.com.cn","cheny@163ccom"]
ret = re.match("\w{4,20}@163\.com$",email)
参考代码:
import re
def main():
"""匹配出163的邮箱地址,且@符号之前有4到20位单词字符,例如hello@163.com"""
email_list = ["lijun@163.com", "wang2_@qq.com", "lining@163.cn", "wang@163.com.cn", "cheny@163ccom"]
# 遍历列表
for email in email_list:
# . 在正则表达式中表示匹配任意一个字符,但是当前需要一个 ".",通过"\" 转义符 转回原生(原来、本来的意义,初始的意义)的意义
ret = re.match("\w{4,20}@163\.com$",email)
if ret:
print("邮箱%s合法的,匹配的内容是:%s" % (email, ret.group()))
else:
print("邮箱%s不合法" % email)
if __name__ == '__main__':
main()
七、匹配分组
字符 | 功能 |
---|---|
| | 匹配左右任意一个表达式 |
(ab) | 将括号中字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
(?P<name>) | 分组起别名 |
(?P=name) | 引用别名为name分组匹配到的字符串 |
1. | :匹配左右任意一个表达式
问题: 同时匹配出 163和126邮箱的合法性(@符号之前有4到20位单词字符)
re.match("\w{4,20}@163\.com$|\w{4,20}@126\.com$","lijun@126.com")
re.match("\w{4,20}@163\.com$|\w{4,20}@126\.com$","lijun@163.com")
2. (ab) : 分组
问题1: 匹配多个邮箱地址
1. re.match("\w{4,20}@(163|126|qq)\.com$","lijun@126.com")
问题2:想取出合法邮箱特定的值,比如取163,126或者邮箱的前缀
In [166]: ret=re.match("(\w{4,20})@(163|126|qq)\.com$","lijun@qq.com")
In [167]: ret.group()
Out[167]: 'lijun@qq.com'
In [168]: ret.group(0)
Out[168]: 'lijun@qq.com'
In [169]: ret.group(1)
Out[169]: 'lijun'
In [170]: ret.group(2)
Out[170]: 'qq'
3. \num : 引用分组num匹配到的字符串
问题:需求(规则): html标签配对验证, 比如<h1>dsafagd</h1> ,标签必须配对
re.match("<(\w+)>.*</\\1>","<h1>你好dsafagd</h1>")
re.match("<(\w+)>.*</\\1>","<h1>你好dsafagd</h2>")
In [188]: print("\1") : "\1" : 转义成特殊的符号的,所以需要"\\1" ,转出原来的意义即反斜杠 \num
4. (?P<name>):分组起别名
5. (?P=name) : 引用别名为name分组匹配到的字符串
问题:问题4:需求:html标签配对验证, 比如<body><h1>dsafagd</h1></body>
1. re.match("<(\w+)><(\w+)>.*</\\2></\\1>","<body><h1>你好dsafagd</h1></body>")
2. re.match("<(\w+)><(\w+)>.*</\\2></\\1>","<body><h1>你好dsafagd</h1></bod>")
3. re.match("<(?P<p1>\w+)><(?P<p2>\w+)>.*</(?P=p2)></(?P=p1)>","<body><h1>你好dsafagd</h1></body>")
八. re模块的高级用法
a>re.search() :查找,搜索, 当搜索到匹配的内容,则返回
问题:匹配微信公众号文章阅读的次数 : "本文章阅读次数: 9998"
re.search("\d+","本文章阅读次数: 9998")
b>re.findall() : 找到所有匹配的数据,返回的是list
问题:找到本文的所有数字 "本文章阅读次数: 9998次,博客的阅读次数: 50"
ret=re.findall("\d+","本文章阅读次数: 9998次,博客的阅读次数: 50")
ret是列表,注意不要使用ret.group()
c> re.sub() : 替换操作
语法:re.sub("正则表达式","替换的内容","查找的字符串或者文本")
问题:将匹配到的阅读次数加1 "本文章阅读次数: 9998次,博客的阅读次数: 50"
In [226]: def add(temp):
...: strNum=temp.group()
...: num=int(strNum)+1
...: return str(num)
...:
...:
In [227]: ret=re.sub("\d+",add,"本文章阅读次数: 9998次,博客的阅读次数: 50")
In [228]: ret
Out[228]: '本文章阅读次数: 9999次,博客的阅读次数: 51'
d> split 根据匹配进行切割字符串,并返回一个列表
语法:re.split("分隔符正则表达式","要分割的文本")
问题: 分离字符串 "wang 18 广州 python"
In [230]: ret=re.split(" |:|-","wang 18-广州:python")
In [231]: ret
Out[231]: ['wang', '18', '广州', 'python']
In [232]: ret[0]
Out[232]: 'wang'
九、贪婪和非贪婪
Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪则相反,总是尝试匹配尽可能少的字符。
在"*","?","+","{m,n}"后面加上?,使贪婪变成非贪婪。
"*","?","+","{m,n}" : 特点,取字符的不确定性,存在贪婪与非贪婪,python默认是贪婪的,在"*","?","+","{m,n}"后面 加 ? ,把贪婪变为非贪婪
非贪婪
*: 0
?: 0
+: 1
{m,n} :m个
re.search("https://.+?\.jpg",img)
十、r的作用
Python中字符串前面加上 r 表示原生字符串
问题:与大多数编程语言相同,正则表达式里使用"\"作为转义字符,这就可能造成反斜杠困扰
re.match("<(\w+)><(\w+)>.*</\\2></\\1>","<body><h1>你好dsafagd</h1></bod>")
ret=re.match(r"<(\w+)><(\w+)>.*</\2></\1>","<body><h1>你好dsafagd</h1><
...: /body>")
把转义符\变为原生的反斜杠
联系方式
QQ:1217675462
欢迎交流