正则表达式
Regular Expression
对输入的字符串进行匹配 看其是否符合某种模式,或提取符合某种模式的字符串
re模块
提供关于正则表达式的工具
re.match(“规则”,“字符串”)x
规则
描述字符
这个规则是单字符匹配 只能匹配一个字符
字符 | 功能 |
---|---|
. | 匹配任意一个字符(除了\n) |
[ ] | 匹配[]中列举的字符 |
\d | 匹配数字,即0-9 |
\D | 匹配非数字 |
\s | 匹配空白 即空格、tab键 |
\S | 匹配非空白 |
\w | 匹配单词字符a-z,A-Z |
\W | 匹配非单词字符 |
^在方括号中 表示取反操作
[^1-5]
表示 匹配非 1-5中的数
若 要求某一个字符是数字 或者a-g可以写成
[1-9a-z]
当表示两个或条件时 中间什么都不用加
描述数量
匹配多个字符相关的格式
字符 | 功能 |
---|---|
* | 匹配前一个字符出现0次或无限次,a* \d* \s* |
+ | 匹配前一个字符出现1次或者无限次 至少一次 a+ \d+ … |
? | 匹配前一个字符出现1次或者0次 |
{m} | 匹配前一个字符出现m次 |
{m,} | 匹配前一个字符至少出现m次 |
{m,n} | 匹配前一个字符出现从m到n次 |
re.match("\d*","a")
'''
上式返回的是 ""
是指a前面的匹配到的空字符串
不是None 只有在匹配不成功的时候才返回None
'''
r (raw)原始字符串
当一个字符串用r描述的时候 让字符串的每一个字符都像原来的样子一样
s = r"\nabc"
'''
若输出s不加r 则输出s会带有换行
现在加有r 则会输出原来输入的样子 \nabc
也可以在正则表达式中使用
'''
s = "\\nabc"
#方法1
re.match("\\\\\w*",s)
#方法2 r
re.match(r"\\\w*")
表示边界
字符 | 功能 |
---|---|
^ | 匹配字符串的开头 |
$ | 匹配字符串的结尾 |
\b | 匹配一个单词的边界 |
\B | 匹配非单词边界 |
^
在方括号中 ^
是取反的意思,但是在外面
表示匹配的字符必须以^
后面的字符开头
s = "short"
re.match("^s",s) #表示匹配字符必须以s开头
$
表示匹配的字符串 必须以$
前面的字符为结尾
s = "long"
re.match("\w+\w$",s)#表示匹配字符串必须以字符结尾
#必须有机会判断最后一个
re.match("\w+s$",s)
\b
表示匹配一个单词的边界 不占位置
它的前一个字符和后一个字符必须是\w
(字母数字)和 \W
(非字母数字),即匹配必须出现在 \w
(字母数字)和 \W
(非字母数字)字符之间的边界上。
It is a dog \bis\b
\B
表示非单词边界 在\B 前或后的字符 下一个字符必须要是字母
bad motherfucker
\Ba\B 表示a 的前后必须有字符
在使用这种有反斜杠的 语法规则时 必须给匹配的规则加r
re.match(r"ba\B","bad")
匹配分组
问题 设置一个正则表达式 匹配0-100的数字
'''
[1-9]\d?$ 包括了1-99
'''
re.match(r"[1-9]\d?$|0|100","100")
'''
[1-9]?\d?$ 表示0-99
第一个问号 表示第一位为0的时候表示没有出现[1-9]中的数 然后把第一位的0交给\d处理 最后加上了一个终结符$
'''
re.match(r"[1-9]?","0")
字符 | 功能 |
---|---|
| | 匹配|左右任意一个表达式 |
(ab) | 将括号中的字符作为一个分组(group) |
\num | 引用第num个分组 匹配到的字符串 |
(?P<name>) | 分组起别名 |
(?P=name) | 引用别名为name分组匹配到的字符串 |
(ab) 分组
用() 包裹起来需要查询的字符串 可以在group中获得
看代码
s = "<h1>黑猫警长</h1>"
re.match(r"<h1>.*</h1>",s)
'''
上式会返回关于获取到的字符的所有信息
'''
r = re.match(r"<h1>.*</h1>",s)
r.group()#会返回获取到的字符信息
#获取到的是 <h1>黑猫警长</h1>
'''
若使用括号分组
'''
re.match(r"<h1>(.*)</h1>",s)
'''
上式返回结果与不带括号 的相同
'''
r = re.match(r"<h1>(.*)</h1>",s)
r.group()#只会返回 黑猫警长
#若正则模式中 有多个括号 如
r = re.match(r"(<h1>).*(</h1>)",s)\
r.groups()#显示所有找到的字符串
r.group()
r.group(0)
r.group(1)
r.group(2)
'''
r.group()
r.group(0) 与r.group() 相同 都是返回匹配到的所有分组
r.group(1) 返回匹配到的第一个分组
r.group(2) 返回匹配到的第二个分组
'''
\num
引用第num个分组匹配到的字符串
当利用正则获取到的一个字符串,在正则模式中还需要再次使用的时候 要用到\num
上代码
'''
若要提取web网页标签中的文本信息
不知道标签的名字 只知道文本内容 在一对标签中
'''
s = "<html><h1>白猫警长</h1></html>"
#常规 有缺陷的提取方法
re.match(r"<.*><.*>.*</.*></.*>",s)
'''
这个方法可以提取到s中的文本内容 但是有缺陷
<html><h1>一只耳</hxxx></h> 这个内容也能提取到 但是是错误的
没有考虑到一对标签的对称
'''
# 使用\num 分组号
re.match(r"<(.*)><(.*)>.*</\2></\1>$",s)
'''
\1 \2 表示 使用前面匹配到的第一个 第二个字符串
'''
#匹配一个邮箱
email = "2601076587@qq.com"
r = re.match(r"(.+)@(163|126|qq|gmail)\.(com|cn|net)$",email)
'''
用() 包裹起来 | 是因为其中的是整个正则表达式的一部分 并不是一个完整的表达式
'''
r.group(0)
(?P<name>)
和(?P=name)
s = "<html><h1>白猫警长</h1></html>"
re.match(r"<(?P<key1>.*)><(?P<key2>.*)>.*</?P=key2></?P=key1>",s)
re模块高级用法
search方法
**语法 **re.search(“正则”,“字符串”)
和match相同 只有单词 和作用不同
match() 是从第一个开始匹配 若第一个字符 不相匹配的话 就会返回None
search方法 是从第一个开始匹配 若第一个字符 不相配 继续匹配下一个字符 直到找到一个相匹配的或者字符串查找结束 查找完成
findall()
找到文中所有符合条件的字符串 以列表的形式返回
sub()
替换字符串中的值
**语法 **re.sub(“正则”,“替换串”,“查找串”)
sub查找所有符合条件的字符串 然后替换
'''
固定替换串
'''
s ="ba bad bast bai bax"
re.sub(r"\wa","cs",s)
'''
动态替换串
把sub中 放替换串的位置 用一个带有返回值的函数代替
这样替换就不会这么死板了 如对价格进行修改
sub底层相当于调用了一个rearch()方法
会有一个返回值 result
result.group()
'''
s ="java100,python200,c++20,c10"
def replace(result):
print(result.group())
r = int(result.group()) + 200
return r
re.sub(r"\d+",replace,s)
“”" 三个引号 本意是保留原来格式的字符串 但是在.py文件中 只是定义了这个字符串 没有给它命名 所以可以当作注释来看 没有使用它 “”"
split()
以某种规则把字符串进行分割
**语法 **re.split(“规则”,“字符串”)
返回的是一个列表
贪婪模式
正则表达式默认是贪婪模式的
所谓贪婪模式如例子
s = "<p>过山车</p>,<html>倾斜头部 眼神注视</html>"
re.match(r"<.+>",s)#本意是想要匹配一个标签
'''
但是由于默认是贪婪模式,所以遇见第一个>时 不会停下 会一直向后找 直到找到最后一个> 停下来
'''
re.match(r"<.+?>",s)#额外加上一个?就关闭了贪婪模式
'''
又如
s = "here is a big number 123-124-125-16288"
r=re.match(r"(.+)(\d+-\d+-\d+-\d+)",s)
r.group(1)
'3-124-125-16288'
r.groups()
('here is a big number 12', '3-124-125-16288')
虽然第一个括号的要求没有包括数字 但是由于是贪婪模式 所以 它会在满足第二个括号要求的前提下 把其他的都给第一个括号 优先满足前面的贪婪模式
第二个括号 要求至少有一个数字 所以就给了第二个括号 一个数字
r=re.match(r"(.+?)(\d+-\d+-\d+-\d+)",s)
r.groups()
('here is a big number ', '123-124-125-16288')
加上一个? 关闭了第一个+的贪婪模式
但是第二个+的贪婪模式并没有关闭 所以会尽可能满足第二个+ 至少有一个数字 最多没有限制
所以分配了 123
'''