目录
1、匹配单个字符
2、匹配多个字符
3、匹配开头结尾
4、匹配分组
说明:在Python中需要通过正则表达式对字符串进行匹配的时候,可以使用re模块
表达式:re.match(正则表达式, 要匹配的字符串) 有返回值说明匹配成功;否则匹配失败。
特别注意:正则表达式的前面必须添加 r 进行标记正则表达式;因为re中字符串需要是正则式,因此其本身不能被python当作特殊字符处理,故用r使得re接收到完整的正则式字符串。
示列:
import re
result = re.match(r"hello", "hello world")
print(result)
result1 = re.match(r"[hH]ello", "hello world")
print(result1)
result2 = re.match(r"HHHello", "hello world")
print(result2)
1、匹配单个字符
以下匹配均只匹配单个字符
字符 | 功能 |
. | 匹配任意1个字符(除了\n) re.match()添加re.S参数后可以匹配\n |
[] | 匹配[]中列举的字符 |
\d | 匹配数字,即0~9 |
\D | 匹配非数字,即不是数字 |
\s | 匹配空白,即空格,tab键 |
\S | 匹配非空白 |
\w | 匹配单词字符,即a-z、A-Z、0-9、_ |
\W | 匹配非单词字符 |
- :表示连续的内容 0-9 a-z A-Z
group() : 获取匹配成功后的内容
# 匹配单个字符
import re
res1 = re.match(r"这是re模块\d", "这是re模块1")
print(res1.group()) # 这是re模块1
res2 = re.match(r"这是re模块\d", "这是re模块9")
print(res2.group()) # 这是re模块9
res3 = re.match(r"这是re模块[1-367]", "这是re模块3")
print(res3.group()) # 这是re模块3
res4 = re.match(r"这是re模块[1-367]", "这是re模块7")
print(res4.group()) # 这是re模块7
res5 = re.match(r"这是re模块[1-3a-cA-D]", "这是re模块D")
print(res5.group()) # 这是re模块D
res6 = re.match(r"这是re模块\s", "这是re模块 D")
print(res6.group()) # 这是re模块
res7 = re.match(r"这是re模块\w", "这是re模块_")
print(res7.group()) # 这是re模块_
2、匹配多个字符
字符 | 功能 |
* | 匹配前一个字符出现0次或者无限次,即可有可无 |
+ | 匹配前一个字符出现1次或者无限次,即至少1次 |
? | 匹配前一个字符出现1次或者0次,即要么有1次,要么没有(非贪婪匹配) |
{m} | 匹配前一个字符出现m次 |
{m,n} | 匹配前一个字符出现从m~n次 |
示例:
import re
# 匹配多个字符
# {m,n} 匹配前一个字符出现从m~n次
res1 = re.match(r"这是re模块\d{1,3}", "这是re模块1")
print(res1.group()) # 这是re模块1
res2 = re.match(r"这是re模块\d{1,3}", "这是re模块123")
print(res2.group()) # 这是re模块123
# {m} 匹配前一个字符出现m次
# \d{11} 数字必须连续出现11次
res1 = re.match(r"\d{11}", "12345678901")
print(res1.group()) # 12345678901
res2 = re.match(r"\d{11}", "12345A678901")
print(res2.group()) # AttributeError: 'NoneType' object has no attribute 'group'
# ?匹配前一个字符出现1次或者0次,即要么有1次,要么没有
# 判断电话取号是否合法
res1 = re.match(r"021-\d{8}", "021-12345678")
print(res1.group()) # 021-12345678
res2 = re.match(r"021-?\d{8}", "02112345678")
print(res2.group()) # 02112345678
res3 = re.match(r"021-?\d{8}", "021-12345678")
print(res3.group()) # 021-12345678
res4 = re.match(r"\d{3,4}-?\d{8}", "0210-12345678")
print(res4.group()) # 0210-12345678
# * 匹配前一个字符出现0次或者无限次,即可有可无
# . 匹配任意1个字符(除了\n)
# 如果一个字符串内容很长并且有很多换行 使用三引号"""或'''
txt_content = '''adshgad
564898
sachoiaus
sachsayogca
asjyha
sajp78adas
958dnouahd8
++0
.
'''
res1 = re.match(r".*", txt_content)
print(res1.group()) # adshgad \n(换行)无法匹配
res2 = re.match(r".*", txt_content, re.S)
print(res2.group()) #添加re.S参数后 匹配html_content里面的所有内容
# + 匹配前一个字符出现1次或者无限次,即至少1次
# . 匹配任意1个字符(除了\n)
res1 = re.match(r".+", "025sdcha")
print(res1.group()) # 025sdcha
res2 = re.match(r".+", "")
print(res2.group()) # AttributeError: 'NoneType' object has no attribute 'group'
3、匹配开头结尾
字符 | 功能 |
^ | 匹配开头字符串 |
$ | 匹配字符串结尾 |
示例1:匹配出,变量名是否有效
import re
def main():
names = ["name1", '_name', '02nmae', '__name__', 'name!', 'name@#']
for name in names:
res = re.match(r"[a-zA-Z_][a-zA-Z0-9_]*", name)
if res:
print("有效的变量名有: {}; 通过正则表达式匹配出来的数据是: {}".format(name, res.group()))
else:
print("无效的变量名有: ", name)
if __name__ == '__main__':
main()
问题:可以看出变量:name!、name@#是不合法的但是match()函数还是有返回值,原因是match()函数自带从开头开始匹配但是不判断结尾。要想match()函数判断结尾需要使用字符:$
示例1:优化
- 注意:此例的判断开头符 ^ 可以省略
import re
def main():
names = ["name1", '_name', '02nmae', '__name__', 'name!', 'name@#']
for name in names:
res = re.match(r"^[a-zA-Z_][a-zA-Z0-9_]*$", name)
if res:
print("有效的变量名有: {}; 通过正则表达式匹配出来的数据是: {}".format(name, res.group()))
else:
print("无效的变量名有: ", name)
if __name__ == '__main__':
main()
字符转义问题
-
1、如果在正则表达式中需要用到某些普通的字符,比如 . ? 等只需要在该字符的前面添加一个反斜杠\进行转义
-
2、使用了[]符代表只匹配一个字符
示例如下:匹配出qq的邮箱地址,且@符号之前有4到20位,例如:123@qq.com
import re
def main():
addrs = ["01552ahsgfhuag@qq.com", "5502@qq.com", "dss15@qq.com", "15sajhaj", "15613@qq.cn"]
for addr in addrs:
# 如果在正则表达式中需要用到某些普通的字符,比如 . ? 等只需要在该字符的前面添加一个反斜杠\进行转义,
# 即出现需要匹配的字符和正则表达式的字符重合了,那么使用反斜杠\对需要匹配的字符进行转义。
res = re.match(r"^[0-9a-zA-Z]{4,20}@qq\.com$", addr)
if res:
print("合法的邮箱有: ", addr)
else:
print("不合法的邮箱有: ", addr)
if __name__ == '__main__':
main()
4、匹配分组
字符 | 功能 |
| | 匹配左右任意一个表达式 |
(ab) | 将括号中的字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
(?P) | 分组起别名(注意要加上括号) |
(?P=name) | 引用别名为name分组匹配到的字符串 |
示列:
import re
res1 = re.match(r"[a-zA-Z0-9_]{4,20}@qq\.com", "hello@qq.com").group()
print(res1) # hello@qq.com
# | 匹配左右任意一个表达式
res2 = re.match(r"[a-zA-Z0-9_]{4,20}|@qq\.com", "@qq.com").group()
print(res2) # @qq.com
# (ab) 将括号中的字符作为一个分组
res3 = re.match(r"[a-zA-Z0-9_]{4,20}@(sohu|qq)\.com", "hello@qq.com").group()
print(res3) # hello@qq.com
# 取得匹配成功之后分组里面的数据 在group里面取得
res4 = re.match(r"[a-zA-Z0-9_]{4,20}@(sohu|qq)\.com", "hello@qq.com").group(1)
print(res4) # qq
res5 = re.match(r"([a-zA-Z0-9_]{4,20})@(sohu|qq)\.com", "hello@qq.com").group(1)
print(res5) # hello 当group(2)时取得结果为:qq
# \num引用分组num匹配到的字符串 要求匹配标签是否为1组即<h1></h1>为1组
html_str = "<h1>hello world</h1>"
res6 = re.match(r"<\w*>.*</\w*>", html_str).group()
print(res6) # <h1>hello world</h1>
html_str2 = "<h1>hello world</h2>"
res6 = re.match(r"<\w*>.*</\w*>", html_str2).group()
print(res6) # <h1>hello world</h2> 此处本不应该匹配成功的,但是还是匹配成功了所以需要修改为第一个标签和最后一个标签要一样
# 修改如下:
res7 = re.match(r"<(\w*)>.*</\1>", html_str2).group()
print(res7) # AttributeError: 'NoneType' object has no attribute 'group'
res8 = re.match(r"<(\w*)>.*</\1>", html_str).group()
print(res8) # <h1>hello world</h1>
html_str3 = "<body><h1>hello world</h1></body>"
res9 = re.match(r"<(\w*)><(\w*)>.*</\2></\1>", html_str3).group()
print(res9) # <body><h1>hello world</h1></body>
# (?P<name>)分组起别名 (?P=name)引用别名为name分组匹配到的字符串
res10 = re.match(r"<(?P<p1>\w*)><(?P<p2>\w*)>.*</(?P=p2)></(?P=p1)>", html_str3).group()
print(res10) # <body><h1>hello world</h1></body>