日志(logging)与正则(re)模块

时间:2022-07-24 08:31:00

logging模块

#日志:日常的流水 =>日志文件,将程序运行过程中的状态或数据进行记录,一般都是记录到日志文件中

#1、logging模块一共分为五个打印级别 debug、info、warning、error、critical

#2、级别本身没有代表信息重要性的区别,只是包含级别信息,可以约定日志的重要性

标准的三流

import sys
# 标准的三流 stdout | stdin | stderr
# stdout和stderr两个是抢cpu工作,没有规定的前后
sys.stdout.write('aaa') # aaa 正常信息的输出,白字输出
sys.stderr.write('aaa') # aaa 异常信息的输出,红字输出
res = sys.stdin.read(2) # 信息的输入,括号里表示打印几个字符
res = sys.stdin.readline() # 信息的输入,readline表示一次打印一行
print(res)

logging的基本配置

import logging
import sys
h1 = logging.FileHandler('a.txt',encoding='utf-8') # 可以往文件里写日志
h2 = logging.StreamHandler() # 可以往控制台打印日志
logging.basicConfig(
# filename='a.txt', # 打印到文件中
# stream=sys.stderr, #打印到控制台
format='%(asctime)s %(name)s %(message)s', # 打印格式
level=logging.ERROR, #或者用数字40表示 日志等级
datefmt='%Y-%m-%d %H:%M:%S', # 时间格式
handlers=[h1,h2] # 可以同时控制打印到文件和控制台上
)
res = logging.getLogger('owen')
res.critical('error')

格式化的全部名称

%(name)s:Logger的名字,并非用户名,详细查看
%(levelno)s:数字形式的日志级别
%(levelname)s:文本形式的日志级别
%(pathname)s:调用日志输出函数的模块的完整路径名,可能没有
%(filename)s:调用日志输出函数的模块的文件名
%(module)s:调用日志输出函数的模块名
%(funcName)s:调用日志输出函数的函数名
%(lineno)d:调用日志输出函数的语句所在的代码行
%(created)f:当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d:输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s:字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d:线程ID。可能没有
%(threadName)s:线程名。可能没有
%(process)d:进程ID。可能没有
%(message)s:用户输出的消息

logging四大成员

import logging
# 四大成员 logger(打印者)、filter(过滤)、handler(句柄)、formatter(格式)
# 1、新建打印者 --生产日志信息
logger = logging.getLogger('owen')
# 2、创建句柄 --控制信息打印位置
stream_handler = logging.StreamHandler() # 打印到控制台
file_handler = logging.FileHandler('文件绝对路径') # 打印到文件
# 3、打印者绑定到句柄
logger.addHandler(file_handler) # 确定生产完信息的输出位置
# 4、设置格式
fmt = logging.Formatter('%(asctime)s %(name)s %(message)s')
# 5、为句柄绑定输出格式
stream_handler.setFormatter(fmt)

多logger共存

import logging
# 1、创建多logger
log1 = logging.getLogger('owen')
log2 = logging.getLogger('zero')
# 2、logger设置级别
log1.setLevel(logging.INFO) # 默认是warning
# 3、设置句柄
h1 = logging.StreamHandler()
# 4、设置句柄级别
# 1)系统句柄默认级别是warning
# 2)自定义的句柄级别默认同logger(不写就和logger级别一样),也可以在logger基础上追加限制
h1.setLevel(logging.ERROR)
# 5、logger绑定句柄
log1.addHandler(h1)
log1.info('aaa')

logging配置基本样貌

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_cmd', 'o_file']
}
}
}

正则re模块

  ----正则:是有语法的字符串 ,用来匹配目标的字符串

单个字符

import re
# 单个字符
print(re.findall(r'b','sdsbafr')) # 把单个b打印出来['b']
# re.I 不区分大小写的匹配
print(re.findall(r'b','ssdbfBDF',flags=re.I)) # ['b', 'B']
# a|b a或b单个字符
print(re.findall(r'a|b','abc123嘿嘿')) # ['a', 'b']
# [a,b] a或,或b单个字符
print(re.findall(r'[a,b]','abc,123,嘿嘿')) # ['a', 'b', ',', ',']
# [^ab] 非a及非b以外所有单字符
print(re.findall(r'[^ab]','abc123黑')) # ['c', '1', '2', '3', '黑']
# [a-z]所有单个小写字母 [A-Z]所有单个大写字母 [0-9] 所有单个数字
print(re.findall(r'[a-z]','abc123嘿嘿')) # ['a', 'b', 'c']
print(re.findall(r'[A-Z]','ab12嘿AB')) # ['A', 'B']
print(re.findall(r'[0-9]','abc123嘿嘿')) # ['1', '2', '3']
# [a-zA-Z0-9]所有小写大小数字的单个字符
print(re.findall(r'[a-zA-Z0-9]','*SDa2.')) # ['S', 'D', 'a', '2']
# .会匹配除\n以外的所有单个字符
print(re.findall(r'.','%sr\n2\t')) # ['%', 's', 'r', '2', '\t']
# re.S能让.匹配所有单个字符
print(re.findall(r'.','%sd\n2\t',flags=re.S)) # ['%', 's', 'd', '\n', '2', '\t']
# \d匹配单个数字 == [0-9]
print(re.findall(r'\d','abc123嘿嘿')) # ['1', '2', '3']
# \w == [a-zA-Z0-9_] 匹配所有单个数字字母下划线 ,汉字理解为字母
print(re.findall(r'\w','ab12呵_呵')) # ['a', 'b', '1', '2', '呵', '_', '呵']
# \s == [\f\n\t\v] 单个空:空格、制表符、换页符
print(re.findall(r'\s','\f\n \t\v')) # ['\x0c', '\n', ' ', '\t', '\x0b']
# \D就是\d的对立面,非数字的所有单个字符,\W就是\w的对立面,\S就是\s对立面
# 建议使用 [0-9] [a-zA-Z0-9_] [\f\n\t\v] [^0-9]
# 不建议使用 \d \w \s \D

正则匹配步骤

1、将r'\\'的正则语法的字符串转换成正则对象'\' , 用来匹配'\'字符的

2、拿着转换后的正则对象去匹配目标字符串

3、将匹配成功的对象打印出来

--re.findall()走的底层在下面,了解即可

  re_obj = re.compile(r'\n')

  res = reobj.findall('\n')

  print(res)   ['\n']

多个字符

import re
# 明确个数的重复
# {n} 匹配重复n个的字符串 只会把重复n个的字符串取出来
print(re.findall(r'a{2}','abcaabbaaa')) # ['aa', 'aa']
print(re.findall(r'ab{2}','aababbabbb')) # ['abb', 'abb']
print(re.findall(r'a{2}b{2}','abaabbabbb')) # ['aabb']
# {n,} 匹配n到无数个,最少重复n个,最多重复无数个,贪婪匹配,优先匹配无数个
print(re.findall(r'ab{2,}','ababbabbbabbbb')) # ['abb', 'abbb', 'abbbb']
# {,n} 相当于{0,n}匹配0到n个,最少0个,最多n个,优先匹配多的
print(re.findall(r'ab{,2}','aababbabbbabbbb')) # ['a', 'ab', 'abb', 'abb', 'abb']
# {n,m} 匹配n搭配m个,优先匹配多的,再考虑少的
print(re.findall(r'ab{1,2}','aababbabbb')) # ['ab', 'abb', 'abb']
# 特殊符号的重复
# * 匹配0到无数个
print(re.findall(r'ab*','aababbabbb')) # ['a', 'ab', 'abb', 'abbb']
# + 匹配1到无数个
print(re.findall(r'ab+','aababbabbb')) # ['ab', 'abb', 'abbb']
# ? 匹配0到1个
print(re.findall(r'ab?','aababbabbb')) # ['a', 'ab', 'ab', 'ab'] # 需求:匹配所有的单词
print(re.findall(r'[a-z]+','abc def hello print')) # ['abc', 'def', 'hello', 'print']
print(re.findall(r'[a-z]+\b','abc def hello print')) # ['abc', 'def', 'hello', 'print'] # \b代表单词的边界,用空格(或者字符串的边界)作为匹配规则,(所以上面的需求加不加\b都一样)
print(re.findall(r'[a-z]+c\b','abc def hello print acb zc')) # 单词边界前面是c,表示单词以c结尾,['abc', 'zc']
print(re.findall(r'[a-z]+c','abc def hello print acb zc')) # 不把边界符带上,会把单词拆开匹配,['abc', 'ac', 'zc']

多行匹配

import re
# 多行匹配
s = '''http://www.baidu.com
https://www.sina.com
https://www.youku.com
'''
# ^代表以什么什么开头,$代表以什么什么结尾,必须结合flags=re.M使用
print(re.findall(r'^http.+com$',s))
# --[] 一个找不到,因为不结合re.M会把s整个看成一个字符串匹配开头和结尾,但是.不匹配\n
print(re.findall(r'^http.+com$',s,re.M))
# --['http://www.baidu.com', 'https://www.sina.com', 'https://www.youku.com']

分组

import re
url = 'www.baidu.com http://www.youku.com'
# 专门处理分组的方法:分组、分组编号、有名分组、取消分组
# 获取域名
print(re.findall(r'www.([a-z]+).com',url)) # ['baidu', 'youku'] # ()代表分组
# findall匹配,如果匹配规则用有分组语法,只存放分组结果
print(re.findall(r'(www).([a-z]+).com',url)) # [('www', 'baidu'), ('www', 'youku')] # 分组的编号,可以以套多个括号分组,编号按左括号的顺序排序,结果按顺序打印出来
print(re.findall(r'(w(w)w.([a-z]+).com)',url)) # 首先是目标字符串匹配到两个正则字符串,所以结果两个
# [('www.baidu.com', 'w','baidu'),('www.youku.com', 'w','youku')]再根据分组,再每个结果里进行排序,放到元组里 # 取消分组,必须写(),但是()里面只是想作为一个整体,而不是分组(因为findall有分组只会显示分组)
# 我们想把()里的数据作为一个整体,()必须写,就需要用到取消分组
# (?:) 表示取消分组
print(re.findall(r'www.(?:[a-z]+).com',url)) # 取消了分组匹配规则['www.baidu.com', 'www.youku.com'] # (?P<名字>) 表示有名分组,<>里的名字就是分组的名字
res = re.match(r'((?:www).(?P<owen>[a-z]+).com)',url) # match必须从头开始匹配,只匹配一次
print(res) # <_sre.SRE_Match object; span=(0, 13), match='www.baidu.com'>
print(res.group(2)) # baidu
print(res.group('owen')) # baidu 可以通过名字把对应的分组取出来
# findall与math
# findall是全文匹配,可以从任何位置开始匹配,匹配多次
# match 是非全文匹配,只能从开头开始匹配,而且只能匹配一次

拆分与替换

import re
s = 'a sd sdf af fa'
# 字符串拆分
print(s.split(' ')) # 以空格拆
# 正则拆分 split(parameter,string)
print(re.split(r' ',s)) # 以空格拆
s = 'sd$sdas@sds&sd'
# 如果想以特殊符号拆分,字符串拆就比较麻烦,正则如下
print(re.split(r'[$@&]',s)) # 替换 sub(parameter,repl,string,count=0)
s = 'python and py python'
print(re.sub(r'python','PYTHON',s)) # PYTHON and py PYTHON
print(re.sub(r'python','PYthon',s,1)) # PYthon and py python # 结合分组可以完成信息的重组与替换
print(re.sub(r'(thon) (and) py (python)',r'|| \3 \1 \2',s))
# py|| python thon and 没有匹配的字符不会被替换,会被带下来,其他分组可以根据索引排序重组