python学习Day20 logging 配置、re正则
标准三流
标准输入流 标准输出流 标准错误流
import sys
标准输入流
#sys.stdin.readline() #input的底层
标准输出流
#sys.stdout .write('输出的讯息') #print() 的底层
标准错误流
#sys .stderr.write('输出的讯息') # 异常及logging默认的打印方式底层
logging模块
# 操作日志的模块
# 日志:日常的流水,将程序运行过程中的状态或数据进行记录,一般都是记录到日志文件中
# 在正常的项目中,项目运行的一些打印信息,采用looging打印到文件中,这个过程就称之为 记录日志
import logging
# logging为默认打印者,名字叫root,配置采用以下方式
h1 = logging.StreamHandler()
h2 = logging.FileHandler('d.log')
logging.basicConfig(
# filename='my.log',
# filemode='w',
# stream=sys.stderr, # 往控制台打印采用具体的输出流
format='%(asctime)s [%(levelname)s]- %(name)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.DEBUG, # 10, 代表DEBUG及DEBUG级别以上都能输出
handlers=[h1, h2]
)
logging.debug("debug")
logging.info("info")
logging.warning("warning")
logging.error("error")
logging.critical("critical")
logging的四大成员
# 1.新建打印者
logger = logging.getLogger("name")
# 2.创建句柄:输出的位置
stream_handler = logging.StreamHandler()
a_file_handler = logging.FileHandler('a.log')
b_file_handler = logging.FileHandler('b.log')
# 3.打印者绑定句柄
logger.addHandler(stream_handler)
logger.addHandler(a_file_handler)
logger.addHandler(b_file_handler)
# 4.设置格式
fmt1 = logging.Formatter('%(asctime)s - %(msg)s')
fmt2 = logging.Formatter('%(asctime)s [%(name)s] - %(msg)s')
# 5.为句柄绑定输出格式
stream_handler.setFormatter(fmt1)
a_file_handler.setFormatter(fmt1)
b_file_handler.setFormatter(fmt2)
6.开始打印日志信息
logger.critical('msg')
多输出者
import logging
# 1.创建logger
log1 = logging.getLogger('Owen')
log2 = logging.getLogger('Zero')
r_log = logging
# 2.logger设置级别
log1.setLevel(logging.DEBUG)
# 3.设置句柄,输出位置
h1 = logging.StreamHandler()
# 4.设置句柄级别:
# 1)系统句柄默认级别warning,
# 2)自定义的句柄级别默认同logger,也可以在logger基础上在加以限制
h1.setLevel(logging.DEBUG)
# 5.logger添加句柄
log1.addHandler(h1)
# log1可以打印DEBUG以上的信息,但往不同位置打印,采用不同句柄的二次级别限制
h2 = logging.FileHandler('c.log')
h2.setLevel(logging.WARNING)
log1.addHandler(h2)
log1.debug('debug')
配置文件的使用
# 1.配置
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'o_fmt1': {
'format': '%(name)s:%(asctime)s - %(message)s'
},
'o_fmt2': {
'format': '%(name)s:%(asctime)s [%(levelname)s] - %(message)s'
}
},
'filters': {},
'handlers': {
'o_cmd': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
'formatter': 'o_fmt1'
},
'o_file': {
'level': 'WARNING',
'class': 'logging.handlers.RotatingFileHandler',
'formatter': 'o_fmt2',
'filename': r'F:\python8期\课堂内容\day20\代码\part4\logging.log', # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5, #日志文件最大个数
'encoding': 'utf-8', # 日志文件的编码
}
},
'loggers': {
'o_owen': {
'level': 'DEBUG',
'handlers': ['o_cmd', 'o_file']
},
'o_zero': {
'level': 'DEBUG',
'handlers': ['o_file']
}
}
}
# 2.加载配置
import logging.config
logging.config.dictConfig(LOGGING_DIC)
# 3.使用
log = logging.getLogger('o_owen')
log.warning('123')
re模块
#正则的匹配步骤,
#1 将正则的语法字符串,转换成正则对象,然后拿着转换后的
# 正则对象 来匹配目标字符串,如遇到特殊语法比如\t
#会先把\n转换为对应的制表符,然后进行匹配制表符
#如\\t ,会先把\\ 转换为\ 这样剩下的\t就没有特殊意义了,直接匹配\t字符
s1='abc,123嘿嘿a_bc\nABC'
#flags=I 匹配的时候不区分大小写的匹配
print(re.findall(r'abc', s1, flags=re.I))
# a|b 匹配a或b单个字符
print(re.findall(r'a|b',s1))
# [abc] 匹配a或b或c单个字符
print(re.findall(r'[abc]',s1))
#[^ab] 匹配非ab之外的所有单个字符
print(re.findall(r'[^ab]',s1))
#[a-z] 匹配所有单个小写字母 [A-Z] 匹配所有单个大写字母 [0-9] 匹配所有单个数字
print(re.findall(r'[a-zA-Z0-9]',s1))
# . 会匹配除\n以外的所有单个字符 在后面加上flags=re.S可以让.匹配所有单个字符
print(re.findall('.',s1,flags=re.S))
#\d 匹配0-9单个数字
print(re.findall('\d',s1))
#\w 匹配 [a-zA-Z0-9_] 将常见的汉字理解为单个字母,也可以匹配
print(re.findall('\w',s1))
#\s 匹配所有空格字符, [\f\n\r\t\v]
print(re.findall('\s',s1))
#\D 就是\d的对立面,匹配非数字的所有单个字符,
# \W就是\w的对立面 匹配非字母数字下划线 的单个字符
# \S 就是\s的对立面匹配所有非空白字符的单个字符
'匹配单个汉字 '
print(re.findall('[\u4e00-\u9fa5]',s1))
#用的时候建议使用 [0-9] [a-z]这种匹配方式 不建议使用\d \w \s这种,因为带\兼容性比较差
匹配多个多个字符
在某个字符后面放大括号{m,n} ,是允许前一个字符至少出现m次,最多出现n次,
m默认不写为0,n默认不写 为最大匹配数量
print(re.findall(r'a{2}b{2}', 'aabbababab')) # ['aabb']
* 前一个字符出现0次到无限次
+ 前一个字符至少1次到无限次
? 前一个字符出现一次或者不出现
\b是匹配单词边界,字符串的结尾也包括
^ 代表以什么开头
$代表以什么结尾.
必须结合flags=re.M来完成多行匹配
# ()代表分组
# findall匹配,如果匹配规则用有分组语法,只存放分组结果
分组是根据左到右的括号匹配到对应的结束括号作为分组顺序
# 专门处理分组的方法:分组,分组编号,有名分组,取消分组
() 分组
(?:) 取消分组,代表这是一个整体
(?p<名字>) 在里面写上名字,就成了有名分组
# findall是全文匹配,可以从任意位置开始,匹配多次
# match非全文匹配,必须从头开始匹配,只能匹配一次 匹配到了返回一个match对象,用group()括号中可以放 索引 第几个分组,如果分组有名字,也可以放名字。就可以获取其中的值
不填默认返回所有值
"""
re模块与正则表达式之间的关系
正则表达式不是python独有的 它是一门独立的技术
所有的编程语言都可以使用正则
但是如果你想在python中使用,你就必须依赖于re模块
正则就是用来筛选字符串中的特定的内容的
书:正则指引
正则的应用场景
1.爬虫
2.数据分析
只要是reg...一般情况下都是跟正则有关
1.想匹配具体的内容 可以直接写完整的内容,不需要写正则
字符组 []
一个字符串里面的表达式都是或的关系
^与$符连用 会精准限制匹配的内容
两者中间写什么 匹配的字符串就必须是什么
多一个也不想少一个也不行
abc|ab 一定要将长的放在前面
^ 直接写在外面 限制字符串的开头
[^] 除了[]写的字符 其他都要
正则在匹配的时候默认都是贪婪匹配(尽量匹配多的)
你可以通过在量词后面加上一个?就可以将贪婪匹配变成非贪婪匹配(惰性匹配)
量词必须跟在正则符号的后面
量词只能能够限制紧挨着它的那一个正则符号
分组:当多个正则符号需要重复多次的时候或者当做一个整体进行其他操作,那么可以分组的形式
分组在正则的语法中就是()
身份证号码是一个长度为15或18个字符的字符串,如果是15位则全部🈶️数字组成,
首位不能为0;如果是18位,则前17位全部是数字,末位可能是数字或x,
下面我们尝试用正则来表示:
"""
# 先学正则(正则表达式书写)
# 在re模块
# while True:
# phone_number = input('please input your phone number : ')
# if len(phone_number) == 11 \
# and phone_number.isdigit()\
# and (phone_number.startswith('13') \
# or phone_number.startswith('14') \
# or phone_number.startswith('15') \
# or phone_number.startswith('16') \
# or phone_number.startswith('17') \
# or phone_number.startswith('18')):
# print('是合法的手机号码')
# else:
# print('不是合法的手机号码')
#
# import re
# phone_number = input('please input your phone number : ')
# if re.match('^(13|14|15|16|17|18)[0-9]{9}$',phone_number):
# print('是合法的手机号码')
# else:
# print('不是合法的手机号码')
# python使用正则必须借助于re模块 或者是支持正则表达式书写的方法
import re
"""
findall
search
match
"""
# res = re.findall('[a-z]+','eva egon jason')
# # findall('正则表达式','带匹配的字符串')
# print(res)
# 找出字符串中符合正则表达式全部内容 并且返回的是一个列表,列表中的元素就是正则匹配到的结果
#
#
# res = re.search('a','eva egon jason')
# print(res) # search不会给你直接返回匹配到的结果 而是给你返回一个对象
# print(res.group()) # 必须调用group才能看到匹配到的结果
"""
注意:
1.search只会依据正则查一次 只要查到了结果 就不会再往后查找
2.当查找的结果不存在的情况下 调用group直接报错
"""
# res1 = re.search('a','eva egon jason')
# # search('正则表达式','带匹配的字符串')
# if res1:
# print(res1.group())
# res = re.match('a','eva egon jason')
# print(res)
# print(res.group())
"""
注意:
1.match只会匹配字符串的开头部分
2.当字符串的开头不符合匹配规则的情况下 返回的也是None 调用group也会报错
"""
# ret = re.split('[ab]', 'abcd') # 先按'a'分割得到''和'bcd',在对''和'bcd'分别按'b'分割
# print(ret) # ['', '', 'cd'] 返回的还是列表
#
#
# ret = re.sub('\d', 'H', 'eva3egon4yuan4',1) # 将数字替换成'H',参数1表示只替换1个
# # sub('正则表达式','新的内容','待替换的字符串',n)
# # """
# # 先按照正则表达式查找所有符合该表达式的内容 统一替换成'新的内容' 还可以通过n来控制替换的个数
# # """
# print(ret) # evaHegon4yuan4
# ret = re.subn('\d', 'H', 'eva3egon4yuan4') # 将数字替换成'H',返回元组(替换的结果,替换了多少次)
# ret1 = re.subn('\d', 'H', 'eva3egon4yuan4',1) # 将数字替换成'H',返回元组(替换的结果,替换了多少次)
# print(ret) # 返回的是一个元组 元组的第二个元素代表的是替换的个数
#
# obj = re.compile('\d{3}') #将正则表达式编译成为一个 正则表达式对象,规则要匹配的是3个数字
# ret = obj.search('abc123eeee') #正则表达式对象调用search,参数为待匹配的字符串
# res1 = obj.findall('347982734729349827384')
# print(ret.group()) #结果 : 123
# print(res1) #结果 : ['347', '982', '734', '729', '349', '827', '384']
# import re
# ret = re.finditer('\d', 'ds3sy4784a') #finditer返回一个存放匹配结果的迭代器
# print(ret) # <callable_iterator object at 0x10195f940>
# print(next(ret).group()) # 等价于ret.__next__()
# print(next(ret).group()) # 等价于ret.__next__()
# print(next(ret).group()) # 等价于ret.__next__()
# print(next(ret).group()) # 等价于ret.__next__()
# print(next(ret).group()) # 等价于ret.__next__()
# print(next(ret).group()) # 等价于ret.__next__() 超出迭代取值的范围 直接报错
# print(next(ret).group()) #查看第一个结果
# print(next(ret).group()) #查看第二个结果
# print([i.group() for i in ret]) #查看剩余的左右结果
# import re
# res = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199812067023')
# 还可以给某一个正则表达式起别名
# res = re.search('^[1-9](?P<password>\d{14})(?P<username>\d{2}[0-9x])?$','110105199812067023')
# print(res.group())
# print(res.group('password'))
# print(res.group(1))
# print(res.group('username'))
# print(res.group(2))
# print(res.group(2))
# print(res.group(1))
# ret1 = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
# ret2 = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com') # 忽略分组优先的机制
# print(ret1,ret2) # ['oldboy'] 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
# ret=re.split("\d+","eva3egon4yuan")
# print(ret) #结果 : ['eva', 'egon', 'yuan']
#
# ret1=re.split("(\d+)","eva3egon4yuan")
# print(ret1) #结果 : ['eva', '3', 'egon', '4', 'yuan']
拆分与替换
拆分
re.split('[, /]','目标字符串’)
拆分的格式 可以填很多种
替换
re.sub() 替换 前面填匹配的格式,然后填替换成的内容,后面放目标字符串。匹配的格式可以分组,并且分组的序号 后面新内容可以用\带序号可以多次使用分组的内容, 使内容重组
loggin模块
日志:记录日常的流水 => 将程序运行过程中的状态或数据进行记录,记录到日志文件中
import logging
logging配置:格式化输出 1)输出的方式 2)输出的格式 3)输出的位置
#基础配置如下:
logging.basicConfig(
filename='my_log.log',
filemode='w', #默认a追加
#stream = sys.stderr, 往控制台打印采用具体的输出流 ,只能往一个地方,要么文件,要么控台
format='%(asctime)s- %(name)s -%(levelname)s - %(module)s-%(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',
level=logging.INFO,) # 10,代表DEBUG及DEBUG级别以上都能输出
五个日志级别,级别本身没有代表信息重要性的级别,人为约定信息的级别。
可以设置级别,打印满足对应级别的信息
logging.info('info') #10
logging.debug('debug') #20
logging.warning('warning') #30
logging.error('error') #40
logging.critical('critical') #50
#不能将日志信息按不同的配置【日志格式,日志种类、等】写到不同的文件
#四大成员:
#1. logger对象
#2. filter 一种过滤规则
#3. handler控制输出的位置句柄,如往文件1、文件2..控制台
#4.formater输出的格式
'''
# 1.logger对象
logger1 = logging.getLogger('O_WEN') #不写默认是root
# 2.filter对象:过滤日志
'''
# 3.handler对象
fh1 = logging.FileHandler('a1.log', encoding='utf-8',) # 默认mode='a',
fh2 = logging.FileHandler('a2.log',encoding='utf-8')
ch = logging.StreamHandler() #打印到控制台
# 4.formater 控制输出格式
formater1 = logging.Formatter(
fmt='%(asctime)s - %(name)s - %(levelname)s - %(module)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S %p',)
formater2 = logging.Formatter(
fmt='%(asctime)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H: %S %p',
)
# 5.绑定logger对象与handler对象
logger1.addHandler(fh1)
logger1.addHandler(fh2)
logger1.addHandler(ch)
# 6.绑定hgandler与formater
fh1.setFormatter(formater1)
fh2.setFormatter(formater1)
ch.setFormatter(formater2)
# 7.设置logger级别,有logger对象与handle对象两层关卡,必须都放行,最终才会放行执行
# 通常二者的级别相同
logger1.setLevel(10)
fh1.setLevel(10)
fh1.setLevel(10)
ch.setLevel(10)
#8使用logger对象产生日志
logger1.info('egon给owen转帐1000个亿美元')
'''
自定义配置loggin

浙公网安备 33010602011771号