正则表达式
需要引入re模块
思考题一
判断多行字符串, 判断哪一行是符合手机号码
import re
cont = '''
aesdf
17811011234
aa1a3hi233rhi3
87156340
affa124564531346546
afa19454132135
'''
cont = '17811011234abc'
# 判断多行字符串, 判断哪一行是符合手机号码
# 编译一个正则表达式
# r 元字符串 内部有转义字符等不进行转换
pattern = re.compile(r'1[3-9]\d{9}') # 匹配手机号 | 编译对象
result = pattern.search(cont) # 只会返回匹配第一个结果 如果没有匹配成功返回None | 从整个字符串的任意位置开始匹配
# span 找到匹配的下标位 起始和结束 | 换行+回车算2个字符
print(pattern, result)
print(result.group(0)) # grouo(0) 获得匹配的第一组数据的结果 | 字符串
print(result.span(0)) # grouo(0) 获得匹配的第一组数据的下标 | 元祖
# cont = '17811011234abc' 能匹配
result = pattern.match(cont) # 从字符串的第一个字符开始匹配 如果第一个字符不匹配就返回None
print(pattern, result)
print(result.group(0)) # 0 可以忽略
print(result.span(0))
元字符
import re
# 元字符
# . 任意字符(除了换行符) | 匹配任意一个
result = re.match(r'.', 'a') # 可以
result = re.match(r'.', '7') # 可以
result = re.match(r'.', '^') # 可以
result = re.match(r'.', '\n') # 不可以
result = re.match(r'.', '\r') # 可以
result = re.match(r'.', '\t') # 可以
result = re.match(r'.', ' ') # 可以
# [] 区间集合 可以匹配任意在中一个
# \d 匹配 0-9数字 [0-9]
# \D 非数字 [^0-9] | 在中括号内 ^ 表示非
# \s 空白字符 空格 tab 换行 回车 [\t\n\r\f\v] | \v 垂直制表符 \f 换页符
# \S 非空白字符
# \w 匹配单词字符 [a-zA-Z0-9_]
# \W 匹配非单词字符 非数字字母下划线
result = re.match(r'\d', '7') # 0-9
result = re.match(r'\d', 'a')
result = re.match(r'[0-9]', '7')
result = re.match(r'[0-46-9]', '5') # 0-4 与 6-9 不包括 5
result = re.match(r'[0-46-9]', '4')
result = re.match(r'[0-46-9]', '9')
result = re.match(r'[0469]', '6') # 0469 其他都不行
result = re.match(r'[hH]', 'h') # Hh 其他都不行
result = re.match(r'天空\d', '天空8号发射成功')
if result is not None:
print('匹配成功')
print(result.group())
else:
print('匹配不成功')
转义字符 反斜线 \
path = r'I:\AIoT智能物联网工程师\AIoT智能物联网\PY高级\PY高级编程\学习代码\3' # 正常的需要加双反斜线表 一条反斜线
result = re.match(r'I:\\', path) # 反斜线不能作结束 就算加了 r 必须加2条反斜线
if result is not None:
print('匹配成功')
print(path, result.re, result.group())
else:
print('匹配不成功')
数量长度
# 表示数量
# * 0次或多次
# + 1次或多次
# ? 0次或1次
# {m} 出现m次
# {m,} 至少出现m次, 可以更多次
# {m,n} 出现m~n次范围
# 首字母大写 后接 0~多个小写字母
resultItems = []
pattern = r'[A-Z][a-z]*'
resultItems.append(re.match(pattern, 'En'))
resultItems.append(re.match(pattern, 'E'))
resultItems.append(re.match(pattern, 'English'))
# 变量名 字母下划线开头 后接之怒数字下滑线
pattern = r'[a-zA-Z_]\w*'
resultItems.append(re.match(pattern, '_name1'))
resultItems.append(re.match(pattern, 'name1'))
resultItems.append(re.match(pattern, '1name1'))
# 0~99
pattern = r'^\d\d?$' # 需要用到 ^ $
pattern = r'^\d{0,2}$' # 也是需要
resultItems.append(re.match(pattern, '0'))
resultItems.append(re.match(pattern, '10'))
resultItems.append(re.match(pattern, '54'))
resultItems.append(re.match(pattern, '99'))
resultItems.append(re.match(pattern, '107')) # 这个如果去除 ^ $ 也能匹配 匹配2个数字
# 匹配密码
# 至少8位最多20 字母数字下划线, 无其他符号
pattern = r'^\w{8,20}$'
resultItems.append(re.match(pattern, '012345'))
resultItems.append(re.match(pattern, '012345678'))
resultItems.append(re.match(pattern, '~012C34a5678'))
resultItems.append(re.match(pattern, '_012C34a5678'))
print('-' * 80)
for result in resultItems:
if result is not None:
print(result.string, result.re, result.group(), '匹配成功')
else:
print('匹配不成功')
匹配163邮箱
# 匹配163邮箱 | 6~18个字符,可使用字母、数字、下划线,需要以字母开头
resultItems = []
pattern = r'^[a-zA-Z]\w{5,17}@163.com$' # 前面占用一个字符 5~17
cont = '''
awhahlf@163.com
affafafafaaaaaaaaaaaaaaaa@163.com
afa_@163.com
225afafaf@163.com
aaaa____@qq.com
aaaa____@163.com
'''
for _ in cont.split('\n'):
resultItems.append(re.match(pattern, _))
print('-' * 80)
for result in resultItems:
if result is not None:
print(result.string, result.re, result.group(), '匹配成功')
else:
print('匹配不成功')
匹配边界
print('-' * 80)
pattern = r'^[a-zA-Z]\w{5,17}@163.com$' # 前面占用一个字符 5~17 | 前面有空格则不匹配
search = re.search(pattern, cont, re.MULTILINE) # 表示多行匹配 re.MULTILINE
if search is not None:
print(search.group())
print('-' * 80)
pattern = r'[^\d]' # 数字取反 | 需要加中括号
resultItems = [re.match(pattern, '12345'), re.match(pattern, 'a12345')]
pattern = r'^\d'
resultItems.append(re.match(pattern, '12345'))
resultItems.append(re.match(pattern, 'a12345'))
pattern = r'.*\bchangsha\b.*'
resultItems.append(re.match(pattern, 'I love changsha too'))
resultItems.append(re.match(pattern, 'I love changshanan too'))
pattern = r'.*changsha\B.*'
resultItems.append(re.match(pattern, 'I love changsha too'))
resultItems.append(re.match(pattern, 'I love changshanan too'))
for result in resultItems:
if result is not None:
print(result.string, result.re, result.group(), '匹配成功')
else:
print('匹配不成功')
分组
# 分组
# | 或者 匹配任意一边表达式 不能贪婪模式
# 0~100数字
resultItems = []
pattern = r'^[1-9]?\d$|100$'
resultItems.append(re.match(pattern, '0'))
resultItems.append(re.match(pattern, '8'))
resultItems.append(re.match(pattern, '08'))
resultItems.append(re.match(pattern, '10'))
resultItems.append(re.match(pattern, '47'))
resultItems.append(re.match(pattern, '100'))
resultItems.append(re.match(pattern, 'a100'))
resultItems.append(re.match(pattern, '1000'))
resultItems.append(re.match(pattern, '01000'))
resultItems.append(re.match(pattern, '101'))
resultItems.append(re.match(pattern, '789'))
# 网易邮箱 这里就不是用中括号
pattern = r'^[a-zA-Z]\w{5,17}@(163|126).com$' # 前面占用一个字符 5~17 | 前面有空格则不匹配
cont = '''
awhahlf@163.com
affafafafaaaaaaaaaaaaaaaa@163.com
afa_@163.com
225afafaf@163.com
aaaa____@126.com
aaaa____@163.com
'''
for _ in cont.split('\n'):
resultItems.append(re.match(pattern, _))
# 匹配html的 <h1>任何内容</h1>
resultItems = []
pattern = r'<([a-zA-Z0-9]+)>.*</\1>'
resultItems.append(re.match(pattern, '<h1>这是标题</h1>'))
resultItems.append(re.match(pattern, '<div>这是div</div>'))
resultItems.append(re.match(pattern, '<div>这是错误的</p>'))
# 网页嵌套标签
pattern = r'<(?P<n1>\w+)><(?P<n2>\w+)>.*</(?P=n2)></(?P=n1)>'
resultItems.append(re.match(pattern, '<div><p>这是嵌套的</p></div>'))
for result in resultItems:
if result is not None:
print(result.string, result.re, result.group(), '匹配成功')
else:
print('匹配不成功')
高级用法
# 高级用法
cont = '''
awhahlf@163.com
affafafafaaaaaaaaaaaaaaaa@163.com
afa_@163.com
225afafaf@163.com
aaaa____@126.com
aaaa____@163.com
'''
# 需要小括号扩住整个 否则只会匹配返回163和126
result = re.findall(r'(^[a-zA-Z]\w{5,17}@(163|126).com$)', cont, re.MULTILINE)
print(result)
for k, (a, b) in enumerate(result):
print(k, a, b)
# sub
"""
针对匹配结果再二次处理
返回repl字符串或者调用repl函数而得到的字符串。如果没有找到模式,则返回字符串不变
需求:将匹配到的阅读次数加1
"""
print(re.sub(r'\d+', '189', 'python = 188')) # 正则替换
print(re.sub(r'\d+', lambda _: str(int(_.group()) + 1), 'python = 188')) # 回调函数的话返回是个对象 | 计算需要int 返回需要str
# split 切割
string = 'hello, world, beijing.'
print(re.split(r'\W+', string))
string = 'info:xiaoZhang 33 shandong'
print(re.split(r':| ', string))
'''
1、验证账号是否合法(字母开头,允许5-16字节,允许字母数字下划线)。
2、验证密码是否合法(以字母开头,长度在6~18之间,只能包含字母、数字和下划线)
3、匹配是否全是汉字:
4、验证日期格式(2020-09-10)
5、验证身份证号码。
'''
resultItems = []
pattern = r'^[a-zA-Z]\w{4,15}$'
resultItems.append(re.match(pattern, 'ab9_7cde'))
resultItems.append(re.match(pattern, '_abc_de'))
resultItems.append(re.match(pattern, '8abc_de'))
pattern = r'^[a-zA-Z]\w{5,17}$'
resultItems.append(re.match(pattern, 'ab9_7cde'))
pattern = r'^[\u4e00-\u9fa5]+$'
resultItems.append(re.match(pattern, '中文'))
# [1000-9999]-[01-12]-[01-31]
pattern = r'^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$'
resultItems.append(re.match(pattern, '2021-11-11'))
for result in resultItems:
if result is not None:
print(result.string, result.re, result.group(), '匹配成功')
else:
print('匹配不成功')
# 太复杂了
# (?:(?:([1-9]\d{5}(?:18|19|(?:[23]\d))\d{2}(?:(?:0[1-9])|(?:10|11|12))(?:(?:[0-2][1-9])|10|20|30|31)\d{3}[0-9Xx])(?!\d))
# 贪婪或不贪婪 默认贪婪 匹配字符多 加? 非贪婪
string = 'this is my tel:188-8888-9999'
result = re.match(r'(.+?)(\d{3,4}-\d{4}-\d{4})', string) # 问号可以不加
if result is not None:
print(result.string, result.re, result.groups(), '匹配成功')
else:
print('匹配不成功')