• day17 正则表达式和日志


    day17 正则表达式和日志

    今日内容

    1. re,正则表达式 -- 从字符串中提取内容
    2. logging,日志

    昨日回顾

    1. 序列化

      1. json(重要,通用)
        • dumps loads 用于网络传输
        • dump load 用于文件存储
      2. pickle(Python私有)
        • dumps loads 用于网络传输
        • dump load 用于文件存储
      • json获取的是字符串,pickle获取的是字节
      • 将一些特殊数据进行转换
    2. hashlib

      • 用于加密和校验
      • md5,sha1,sha256,sha512
      • 字符串 -- 字节 -- 密文
      • 加密不可逆
      import hashlib
      md5obj = hashlib.md5('要加的盐'.encode('utf-8'))
      md5obj.update('要加密的内容'.encode('utf-8'))
      print(md5.hexdigest())
      
      • 加盐:
        • 固定加盐
        • 动态加盐
    3. collections

      1. Counter
      2. 有序字典,OrderedDict
      3. 默认字典,defaultdict
      4. 双端队列 队列,栈
      5. 命名元组
    4. 软件开发规范

      ----blog_demo
          |----bin
          |    |----start.py
          |----conf
          |    |----setting.py
          |----core
          |    |----src.py
          |----db
          |    |----userinfo
          |----file_tree.py
          |----lib
          |    |----commom.py
          |----log
      

    今日内容详细

    re,正则表达式

    re,也就是正则表达式,用来从字符串中获取我们想要的内容:

    import re
    a = 'alex,meet,eva_j'
    print(re.findall('e', a))    # findall放来的两个参数为:参数1用来传入要查找的内容,参数2用来传入原来的字符串
    
    输出的结果为:['e', 'e', 'e', 'e']
    

    元字符

    正则表达式的当然不仅仅能查找这种简单地字符。正则表达式真正的强大之处在于它无所不包的匹配规则。这一套匹配规则对于所有语言来说都是通用的,通过一个个元字符组合而成:

    元字符 匹配内容
    w 匹配字母(包括中文)、数字或下划线
    W 匹配除字母(包括中文)、数字或下划线以外的字符
    s 匹配任意空白字符
    S 匹配任意非空白字符
    d 匹配任意数字
    D 匹配任意非数字字符
    A或^ 从字符串的开头匹配
    或& 从字符串的结尾匹配
    . 匹配任意字符,除了换行符。当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符
    [0-9a-zA-Z] 用于匹配特定范围的数字和字母,中间不能有空格和逗号
    * 匹配0个或多个左边的字符,贪婪匹配(匹配尽可能长的内容)
    + 匹配1个或多个左边的字符,贪婪匹配
    ? 匹配0个或1个左边的字符,非贪婪匹配。也可以用来将*和+转换为非贪婪匹配模式
    {n} 精准匹配n个前面的字符
    {n, m} 匹配n到m个前面的字符片段,贪婪匹配
    a|b a或者b,优先匹配a
    () 匹配括号内的表达式,也表示一个组

    正则表达式的使用方法为:

    s = 'alex1, 哈啰,123,meet!@'
    print(re.findall('w', s))    # 匹配数字字母(包括中文)字符串
    print(re.findall('W', s))
    输出的结果为:
    ['a', 'l', 'e', 'x', '1', '哈', '啰', '1', '2', '3', 'm', 'e', 'e', 't']
    [',', ' ', ',', ',', '!', '@']
    
    s1 = 'alex w 
    , dal	,sdjfl'
    print(re.findall('s', s1))    # 匹配空白字符
    print(re.findall('S', s1))    # 匹配非空白字符
    输出的结果为:
    [' ', ' ', '
    ', ' ', '	']
    ['a', 'l', 'e', 'x', 'w', ',', 'd', 'a', 'l', ',', 's', 'd', 'j', 'f', 'l']
    
    s2 = 'a1b2c3'
    print(re.findall('d', s2))    # 匹配所有数字
    print(re.findall('D', s2))    # 匹配所有非数字
    输出的结果为:
    ['1', '2', '3']
    ['a', 'b', 'c']
    
    s3 = 'alex'
    print(re.findall('Aa', s3))    # 从开头匹配
    print(re.findall('^a', s3))
    print(re.findall('x', s3))    # 从结尾匹配
    print(re.findall('x$', s3))
    输出的结果为:
    ['a']
    ['a']
    ['x']
    ['x']
    
    s4 = 'abc a12
    3!@	#中文_'
    print(re.findall('.', s4))    # 匹配任意字符(换行符除外)
    print(re.findall('
    ', s4))
    print(re.findall('.', s4, re.DOTALL))    # 匹配包括换行符之内的任意字符
    输出的结果为:
    ['a', 'b', 'c', ' ', 'a', '1', '2', '3', '!', '@', '	', '#', '中', '文', '_']
    ['
    ']
    ['a', 'b', 'c', ' ', 'a', '1', '2', '
    ', '3', '!', '@', '	', '#', '中', '文', '_']
    
    s5 = 'al ex()123!@'
    print(re.findall('[0-9]', s5))    # 匹配范围内的数字
    print(re.findall('[0-9a-zA-Z]', s5))    # 匹配范围内的数字和字母
    输出的结果为:
    ['1', '2', '3']
    ['a', 'l', 'e', 'x', '1', '2', '3']
    
    s6 = 'a.l e!x123'
    print(re.findall('[.]', s6))    # 查找特定的字符“.”
    print(re.findall('.', s6))    # 查找任意字符
    print(re.findall('[^.]', s6))    # 查找除了“.”之外的所有字符
    输出的结果为:
    ['.']
    ['a', '.', 'l', ' ', 'e', '!', 'x', '1', '2', '3']
    ['a', 'l', ' ', 'e', '!', 'x', '1', '2', '3']
    
    s7 = 'alex-meet-leeek'
    print(re.findall('e*', s7))    # 查找0个或多个字符e,贪婪匹配
    print(re.findall('e+', s7))    # 匹配1个或多个字符e,贪婪匹配
    print(re.findall('e?', s7))    # 匹配0个或1个字符e,非贪婪匹配
    print(re.findall('e{2}', s7))   # 匹配刚好2个字符e
    print(re.findall('e{1,2}', s7))    # 匹配1到2个字符2,贪婪匹配,打括号里面不能有空格
    输出的结果为:
    ['', '', 'e', '', '', '', 'ee', '', '', '', 'eee', '', '']
    ['e', 'ee', 'eee']
    ['', '', 'e', '', '', '', 'e', 'e', '', '', '', 'e', 'e', 'e', '', '']
    ['ee', 'ee']
    ['e', 'ee', 'ee', 'e']
    
    s8 = 'alex-meet-leeek'
    print(re.findall('a|e', s8))   # 查找a或e,优先查找a
    输出的结果为:['a', 'e', 'e', 'e', 'e', 'e', 'e']
    
    s9 = 'alex-meeet-leeek'
    print(re.findall('e(e)e', s9))    # 分组,对于findall方法只返回括号内的字符,对于search方法则返回整个表达式结构
    print(re.search('e(e)e', s9).group())
    print(re.findall('m(ee)e', s9))
    print(re.findall('m(?:ee)e', s9))    # 分组,返回整个正则表达式结构
    输出的结果为:
    ['e', 'e']
    eee
    ['ee']
    ['meee']
    

    接下来,我们就通过一些练习题,更加深入理解正则表达式的用法。

    有如下字符串:'alex_sb ale123_sb wu12sir_sb wusir_sb ritian_sb 的 alex wusir ',找到其中所有带_sb的内容。要求,输出结果中也要包含_sb

    import re
    s = 'alex_sb ale123_sb wu12sir_sb wusir_sb ritian_sb 的 alex wusir '
    print(re.findall('w[(?:.+?)]_sb', s))    # 第二个?用来让+变成非贪婪匹配
    print(re.findall('w[a-z0-9]+_sb', s))
    print(re.findall('(w.+?_sb) ', s))
    
    输出结果全都为:
    ['alex_sb', 'ale123_sb', 'wu12sir_sb', 'wusir_sb', 'ritian_sb']
    

    有字符串"1-2*(60+(-40.35/5)-(-4*3))"

    1. 请找出字符串中的所有整数
    2. 请找出字符串中的所有数字(包含小数)
    3. 请找出所有的数字(正数、负数和小数)
    import re
    s = "1-2*(60+(-40.35/5)-(-4*3))"
    print(re.findall('d+', s))
    print(re.findall('d+.?d*', s))
    print(re.findall('-?d+.?d*', s))
    
    输出的结果为:
    ['1', '2', '60', '40', '35', '5', '4', '3']
    ['1', '2', '60', '40.35', '5', '4', '3']
    ['1', '-2', '60', '-40.35', '5', '-4', '3']
    

    请找出字符串"http://blog.csdn.net/make164492212@163.com/article/details/51656638"中的邮箱。

    import re
    s = "http://blog.csdn.net/make164492212@163.com/article/details/51656638"
    print(re.findall('w+@w+.w+', s))
    
    输出的结果为:['make164492212@163.com']
    

    请找出下列字符串中的

    1. 所有形如1995-04-27的时间
    2. 形如1980-04-27:1980-04-27的时间
    import re
    s = '''
    时间就是1995-04-27,2005-04-27
    1999-04-27 老男孩教育创始人
    老男孩老师 alex 1980-04-27:1980-04-27
    2018-12-08
    '''
    print(re.findall('d{4}-d{2}-d{2}', s))
    print(re.findall('(S+:S+)'))
    
    输出的结果为:
    ['1995-04-27', '2005-04-27', '1999-04-27', '1980-04-27', '1980-04-27', '2018-12-08']
    ['1980-04-27:1980-04-27']
    

    匹配字符串"1231,11,2,1,-1,12.34545,abc,ssed"中的浮点数

    import re
    s = "1231,11,2,1,-1,12.34545,abc,ssed"
    print(re.findall('d+.d+', s))
    
    输出的结果为:
    ['12.34545']
    

    匹配字符串"1231231,324233,123,1123,2435,1234,2546,23451324,3546354,13241234"中可能的QQ号(5-11位)。

    import re
    s = "1231231,324233,123,1123,2435,1234,2546,23451324,3546354,13241234"
    print(re.findall('d{5,11}', s))
    
    输出的结果为:
    ['1231231', '324233', '23451324', '3546354', '13241234']
    

    有下面一个长数据,请找出其中a标签中href后的网址(如http://www.cnblogs.com/guobaoyuan/articles/7087629.html)。

    import re
    msg = '''
    <div id="cnblogs_post_body" class="blogpost-body"><h3><span style="font-family: 楷体;">python基础篇</span></h3>
    <p><span style="font-family: 楷体;">&nbsp; &nbsp;<strong><a href="http://www.cnblogs.com/guobaoyuan/p/6847032.html" target="_blank">python 基础知识</a></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/p/6627631.html" target="_blank">python 初始python</a></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<strong><a href="http://www.cnblogs.com/guobaoyuan/articles/7087609.html" target="_blank">python 字符编码</a></strong></strong></span></p>
    <p><span style="font-family: 楷体;"><strong><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/articles/6752157.html" target="_blank">python 类型及变量</a></strong></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/p/6847663.html" target="_blank">python 字符串详解</a></strong></span></p>
    <p><span style="font-family: 楷体;">&nbsp; &nbsp;<strong><a href="http://www.cnblogs.com/guobaoyuan/p/6850347.html" target="_blank">python 列表详解</a></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/p/6850496.html" target="_blank">python 数字元祖</a></strong></span></p>
    <p><span style="font-family: 楷体;">&nbsp; &nbsp;<strong><a href="http://www.cnblogs.com/guobaoyuan/p/6851820.html" target="_blank">python 字典详解</a></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<strong> <a href="http://www.cnblogs.com/guobaoyuan/p/6852131.html" target="_blank">python 集合详解</a></strong></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/articles/7087614.html" target="_blank">python 数据类型</a>&nbsp;</strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/p/6752169.html" target="_blank">python文件操作</a></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/p/8149209.html" target="_blank">python 闭包</a></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/articles/6705714.html" target="_blank">python 函数详解</a></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/articles/7087616.html" target="_blank">python 函数、装饰器、内置函数</a></strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/articles/7087629.html" target="_blank">python 迭代器 生成器</a>&nbsp;&nbsp;</strong></span></p>
    <p><span style="font-family: 楷体;"><strong>&nbsp; &nbsp;<a href="http://www.cnblogs.com/guobaoyuan/articles/6757215.html" target="_blank">python匿名函数、内置函数</a></strong></span></p>
    </div>
    '''
    print(re.findall('href="(.+?)"'))
    
    输出的结果为:
    ['http://www.cnblogs.com/guobaoyuan/p/6847032.html', 'http://www.cnblogs.com/guobaoyuan/p/6627631.html', 'http://www.cnblogs.com/guobaoyuan/articles/7087609.html', 'http://www.cnblogs.com/guobaoyuan/articles/6752157.html', 'http://www.cnblogs.com/guobaoyuan/p/6847663.html', 'http://www.cnblogs.com/guobaoyuan/p/6850347.html', 'http://www.cnblogs.com/guobaoyuan/p/6850496.html', 'http://www.cnblogs.com/guobaoyuan/p/6851820.html', 'http://www.cnblogs.com/guobaoyuan/p/6852131.html', 'http://www.cnblogs.com/guobaoyuan/articles/7087614.html', 'http://www.cnblogs.com/guobaoyuan/p/6752169.html', 'http://www.cnblogs.com/guobaoyuan/p/8149209.html', 'http://www.cnblogs.com/guobaoyuan/articles/6705714.html', 'http://www.cnblogs.com/guobaoyuan/articles/7087616.html', 'http://www.cnblogs.com/guobaoyuan/articles/7087629.html', 'http://www.cnblogs.com/guobaoyuan/articles/6757215.html']
    

    正则表达式常用方法

    除了findall外,正则表达式的常用方法还有search,match等:

    import re
    s = 'alexmeet'
    print(re.findall('e', s))
    print(re.search('e', s))    # 从字符串任意位置进行匹配,查找到一个就停止,返回的是match对象,如果找不到则返回None
    print(re.search('e', s).group())    # 将match对象转换为字符串
    print(re.match('e', s))    # 从字符串的开头位置进行匹配,查找到返回match对象,查找不到返回None
    print(re.match('a', s).group())
    
    输出的结果为:
    ['e', 'e', 'e']
    <_sre.SRE_Match object; span=(2, 3), match='e'>
    e
    None
    a
    

    search方法和match方法的比较:

    • search方法从字符串任意位置进行匹配,查找到一个就停止
    • match方法从字符串开始位置进行匹配,找不到返回None

    除了上面的几个方法,re中还有一些不常用但也很有用的方法:

    import re
    s1 = 'alex wusir,日天,太白;女神;肖锋:吴超'
    print(re.split('[ :;,:;,]', s1))    # split分割
    输出的结果为:
    ['alex', 'wusir', '日天', '太白', '女神', '肖锋', '吴超']
    
    s2 = 'barry是最好的讲师,barry就是一个普通老师,请不要将barry当男神对待。'
    print(re.sub('barry', 'meet', s2))    # sub替换
    输出的结果为:
    meet是最好的讲师,meet就是一个普通老师,请不要将meet当男神对待。
    
    obj = re.compile('d{2}')    # compile 定义匹配规则
    print(obj.findall('alex12345'))
    输出的结果为:
    ['12', '34']
    
    it = re.finditer('e', 'meet,alex')    # 返回一个迭代器
    print(it)
    print(next(it))
    print(next(it).group())
    输出的结果为:
    <callable_iterator object at 0x0000021E54F2AC50>
    <_sre.SRE_Match object; span=(1, 2), match='e'>
    e
    
    s = '<h1>hello</h1>'
    ret = re.search('<(?P<h>w+)>(?P<h1>w+)<(?P<h2>/w+)>')    # 给分组取名字
    print(ret.group('h'))
    print(ret.group('h1'))
    print(ret.group('h2'))
    返回的结果为:
    h1
    hello
    /h1
    

    面试题:

    1. 什么是贪婪匹配和非贪婪匹配?
    2. search和match的区别?

    logging,日志

    logging也就是日志,其主要作用于有:

    1. 记录程序运行的状态(时间,文件名,报错行数,错误信息)
    2. 用户的喜好(分析用户的一些喜好和操作)
    3. 银行(账户流水)

    日志一共分为五个级别:

    序号 错误名 含义 级别
    1 debug 调试 10
    2 info 信息 20
    3 warning 警告 30
    4 error 错误 40
    5 critical 危险 50

    一般情况下,日志默认报告级别在30以上的事件。

    基础版日志

    基础版的日志是Python已经写好了的,可以直接调用:

    import logging
    
    logging.basicConfig(
        level=10,
        format="%(asctime)s %(name)s %(filename)s %(lineno)s %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
        filename='test.log',
        filemode='a', )
    logging.debug('这是调试')
    logging.info('这是信息')
    logging.warning('这是警告')
    logging.error('这是错误')
    logging.error('这是危险')
    

    窗口中没又打印出任何信息,日志全部被写入到文件text.log中。但是因为编码默认是gbk,所以中文出现了乱码。虽然可以通过更改编码读取文件,但是基础版的日志是没有办法指定编码方法的。

    1569680789354

    有了日志之后,我们可以通过日志的方法与用户交互,而避免报错:

    import logging
    
    logging.basicConfig(
        level=10,
        format="%(asctime)s %(name)s %(filename)s %(lineno)s %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",)
    num = input('请输入数字:')
    try:
        num = int(num)
        print(num)
    except ValueError:
        logging.warning('字符串不能强行转换成数字!')
        
    输出的结果为:
    请输入数字:a
    2019-09-28 22:30:56 root exercise.py 165 字符串不能强行转换成数字!
    

    基础版日志调用非常方便,但是有两个缺点:

    1. 编码默认为gbk,且不可修改
    2. 屏幕显示和文件存储不能同时有

    因为这两个缺点,我们更常用的是进阶版的日志。

    进阶版日志

    进阶版日志是我们自己组装实现的,是通过二次开发获得的,其基本用法为:

    import logging
    logger = logging.getLogger()    # 创建一个空架子
    fh = logging.FileHandler('test.log', mode='a', encoding='utf-8')    # 创建一个文件句柄,用来记录日志(文件流)
    ch = logging.StreamHandler()    # 创建一个屏幕流,打印记录的内容
    f_str = logging.Formatter('%(asctime)s %(name)s %(filename)s %(lineno)s %(message)s')    # 定义一个记录日志的格式
    logger.level = 10    # 设置日志记录的级别
    fh.setFormatter(f_str)    # 给文件句柄设置记录内容的格式
    ch.setFormatter(f_str)    # 给中控台设置记录内容的格式
    logger.addHandler(fh)    # 将文件句柄添加到logger对象中
    logger.addHandler(ch)    # 将中控台添加到logger对象中
    
    logger.debug("这是调试")
    logger.info("这是信息")
    logger.warning("这是警告")
    logger.error("这是错误")
    logger.critical("这是危险")
    
    

    这次屏幕和文件中都出现了日志信息,且中文也不需要转编码即可正常显示。

    1569681846706

  • 相关阅读:
    参考阿里规范,优秀的 Java 项目代码该如何分层?
    SpringBoot 中实现跨域的5种方式
    美团一面:你既然写过Mybatis插件,说说它底层是怎么加载一个自定义插件的
    陌陌面试官:说说Spring AOP 的原理、SpringMVC 的处理过程?
    这16条规范代码,同事,拍桌子 大喊 “666”
    微服务很简单,用一张架构图了解一下
    K8S部署Metrics-Server服务
    cookie
    html标签默认样式整理
    html 语义化标签
  • 原文地址:https://www.cnblogs.com/shuoliuchina/p/11605320.html
Copyright © 2020-2023  润新知