日志(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')

格式化的全部名称

%(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:用户输出的消息
View Code

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']
        }
    }
}
View Code

正则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  没有匹配的字符不会被替换,会被带下来,其他分组可以根据索引排序重组
posted @ 2019-05-09 22:16  hesujian  阅读(324)  评论(0编辑  收藏  举报