日志(logging)与正则(re)模块
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')
格式化的全部名称
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
%(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配置基本样貌
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 没有匹配的字符不会被替换,会被带下来,其他分组可以根据索引排序重组