常用模块


一 time与datetime模块
  • 二 random模块
  • 三 os模块
  • 四 sys模块
  • 五 shutil模块
  • 六 json&pickle模块
  • 七 shelve模块
  • 八 xml模块
  • 九 configparser模块
  • 十 hashlib模块
  • 十一 suprocess模块
  • 十二 logging模块
  • 十三 re模块
  •  详细参考官网

    原理图:https://pan.baidu.com/s/1skWyTT7

    #logger:产生日志的对象
    
    #Filter:过滤日志的对象
    
    #Handler:接收日志然后控制打印到不同的地方,FileHandler用来打印到文件中,StreamHandler用来打印到终端
    
    #Formatter对象:可以定制不同的日志格式对象,然后绑定给不同的Handler对象使用,以此来控制不同的Handler的日志格式
    '''
    critical=50
    error =40
    warning =30
    info = 20
    debug =10
    '''
    
    
    import logging
    
    #1、logger对象:负责产生日志,然后交给Filter过滤,然后交给不同的Handler输出
    logger=logging.getLogger(__file__)
    
    #2、Filter对象:不常用,略
    
    #3、Handler对象:接收logger传来的日志,然后控制输出
    h1=logging.FileHandler('t1.log') #打印到文件
    h2=logging.FileHandler('t2.log') #打印到文件
    h3=logging.StreamHandler() #打印到终端
    
    #4、Formatter对象:日志格式
    formmater1=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S %p',)
    
    formmater2=logging.Formatter('%(asctime)s :  %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S %p',)
    
    formmater3=logging.Formatter('%(name)s %(message)s',)
    
    
    #5、为Handler对象绑定格式
    h1.setFormatter(formmater1)
    h2.setFormatter(formmater2)
    h3.setFormatter(formmater3)
    
    #6、将Handler添加给logger并设置日志级别
    logger.addHandler(h1)
    logger.addHandler(h2)
    logger.addHandler(h3)
    logger.setLevel(10)
    
    #7、测试
    logger.debug('debug')
    logger.info('info')
    logger.warning('warning')
    logger.error('error')
    logger.critical('critical')

    五 Logger与Handler的级别

    logger是第一级过滤,然后才能到handler,我们可以给logger和handler同时设置level,但是需要注意的是

    Logger is also the first to filter the message based on a level — if you set the logger to INFO, and all handlers to DEBUG, you still won't receive DEBUG messages on handlers — they'll be rejected by the logger itself. If you set logger to DEBUG, but all handlers to INFO, you won't receive any DEBUG messages either — because while the logger says "ok, process this", the handlers reject it (DEBUG < INFO).
    
    
    
    #验证
    import logging
    
    
    form=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S %p',)
    
    ch=logging.StreamHandler()
    
    ch.setFormatter(form)
    # ch.setLevel(10)
    ch.setLevel(20)
    
    l1=logging.getLogger('root')
    # l1.setLevel(20)
    l1.setLevel(10)
    l1.addHandler(ch)
    
    l1.debug('l1 debug')
    重要,重要,重要!!!

    六 Logger的继承(了解)

    import logging
    
    formatter=logging.Formatter('%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
                        datefmt='%Y-%m-%d %H:%M:%S %p',)
    
    ch=logging.StreamHandler()
    ch.setFormatter(formatter)
    
    
    logger1=logging.getLogger('root')
    logger2=logging.getLogger('root.child1')
    logger3=logging.getLogger('root.child1.child2')
    
    
    logger1.addHandler(ch)
    logger2.addHandler(ch)
    logger3.addHandler(ch)
    logger1.setLevel(10)
    logger2.setLevel(10)
    logger3.setLevel(10)
    
    logger1.debug('log1 debug')
    logger2.debug('log2 debug')
    logger3.debug('log3 debug')
    '''
    2017-07-28 22:22:05 PM - root - DEBUG -test:  log1 debug
    2017-07-28 22:22:05 PM - root.child1 - DEBUG -test:  log2 debug
    2017-07-28 22:22:05 PM - root.child1 - DEBUG -test:  log2 debug
    2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test:  log3 debug
    2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test:  log3 debug
    2017-07-28 22:22:05 PM - root.child1.child2 - DEBUG -test:  log3 debug
    '''

    七 应用

    """
    logging配置
    """
    
    import os
    import logging.config
    
    # 定义三种日志输出格式 开始
    
    standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                      '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字
    
    simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
    
    id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'
    
    # 定义日志输出格式 结束
    
    logfile_dir = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
    
    logfile_name = 'all2.log'  # log文件名
    
    # 如果不存在定义的日志目录就创建一个
    if not os.path.isdir(logfile_dir):
        os.mkdir(logfile_dir)
    
    # log文件的全路径
    logfile_path = os.path.join(logfile_dir, logfile_name)
    
    # log配置字典
    LOGGING_DIC = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': standard_format
            },
            'simple': {
                'format': simple_format
            },
        },
        'filters': {},
        'handlers': {
            #打印到终端的日志
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',  # 打印到屏幕
                'formatter': 'simple'
            },
            #打印到文件的日志,收集info及以上的日志
            'default': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
                'formatter': 'standard',
                'filename': logfile_path,  # 日志文件
                'maxBytes': 1024*1024*5,  # 日志大小 5M
                'backupCount': 5,
                'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
            },
        },
        'loggers': {
            #logging.getLogger(__name__)拿到的logger配置
            '': {
                'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                'level': 'DEBUG',
                'propagate': True,  # 向上(更高level的logger)传递
            },
        },
    }
    
    
    def load_my_logging_cfg():
        logging.config.dictConfig(LOGGING_DIC)  # 导入上面定义的logging配置
        logger = logging.getLogger(__name__)  # 生成一个log实例
        logger.info('It works!')  # 记录该文件的运行状态
    
    if __name__ == '__main__':
        load_my_logging_cfg()
    logging配置文件
    """
    MyLogging Test
    """
    
    import time
    import logging
    import my_logging  # 导入自定义的logging配置
    
    logger = logging.getLogger(__name__)  # 生成logger实例
    
    
    def demo():
        logger.debug("start range... time:{}".format(time.time()))
        logger.info("中文测试开始。。。")
        for i in range(10):
            logger.debug("i:{}".format(i))
            time.sleep(0.2)
        else:
            logger.debug("over range... time:{}".format(time.time()))
        logger.info("中文测试结束。。。")
    
    if __name__ == "__main__":
        my_logging.load_my_logging_cfg()  # 在你程序文件的入口加载自定义logging配置
        demo()
    使用
    注意注意注意:
    
    
    #1、有了上述方式我们的好处是:所有与logging模块有关的配置都写到字典中就可以了,更加清晰,方便管理
    
    
    #2、我们需要解决的问题是:
        1、从字典加载配置:logging.config.dictConfig(settings.LOGGING_DIC)
    
        2、拿到logger对象来产生日志
        logger对象都是配置到字典的loggers 键对应的子字典中的
        按照我们对logging模块的理解,要想获取某个东西都是通过名字,也就是key来获取的
        于是我们要获取不同的logger对象就是
        logger=logging.getLogger('loggers子字典的key名')
    
        
        但问题是:如果我们想要不同logger名的logger对象都共用一段配置,那么肯定不能在loggers子字典中定义n个key   
     'loggers': {    
            'l1': {
                'handlers': ['default', 'console'],  #
                'level': 'DEBUG',
                'propagate': True,  # 向上(更高level的logger)传递
            },
            'l2: {
                'handlers': ['default', 'console' ], 
                'level': 'DEBUG',
                'propagate': False,  # 向上(更高level的logger)传递
            },
            'l3': {
                'handlers': ['default', 'console'],  #
                'level': 'DEBUG',
                'propagate': True,  # 向上(更高level的logger)传递
            },
    
    }
    
        
    #我们的解决方式是,定义一个空的key
        'loggers': {
            '': {
                'handlers': ['default', 'console'], 
                'level': 'DEBUG',
                'propagate': True, 
            },
    
    }
    
    这样我们再取logger对象时
    logging.getLogger(__name__),不同的文件__name__不同,这保证了打印日志时标识信息不同,但是拿着该名字去loggers里找key名时却发现找不到,于是默认使用key=''的配置
    !!!关于如何拿到logger对象的详细解释!!!
    另外一个django的配置,瞄一眼就可以,跟上面的一样
    #logging_config.py
    LOGGING = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]'
                          '[%(levelname)s][%(message)s]'
            },
            'simple': {
                'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
            },
            'collect': {
                'format': '%(message)s'
            }
        },
        'filters': {
            'require_debug_true': {
                '()': 'django.utils.log.RequireDebugTrue',
            },
        },
        'handlers': {
            #打印到终端的日志
            'console': {
                'level': 'DEBUG',
                'filters': ['require_debug_true'],
                'class': 'logging.StreamHandler',
                'formatter': 'simple'
            },
            #打印到文件的日志,收集info及以上的日志
            'default': {
                'level': 'INFO',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
                'filename': os.path.join(BASE_LOG_DIR, "xxx_info.log"),  # 日志文件
                'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
                'backupCount': 3,
                'formatter': 'standard',
                'encoding': 'utf-8',
            },
            #打印到文件的日志:收集错误及以上的日志
            'error': {
                'level': 'ERROR',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
                'filename': os.path.join(BASE_LOG_DIR, "xxx_err.log"),  # 日志文件
                'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
                'backupCount': 5,
                'formatter': 'standard',
                'encoding': 'utf-8',
            },
            #打印到文件的日志
            'collect': {
                'level': 'INFO',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,自动切
                'filename': os.path.join(BASE_LOG_DIR, "xxx_collect.log"),
                'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
                'backupCount': 5,
                'formatter': 'collect',
                'encoding': "utf-8"
            }
        },
        'loggers': {
            #logging.getLogger(__name__)拿到的logger配置
            '': {
                'handlers': ['default', 'console', 'error'],
                'level': 'DEBUG',
                'propagate': True,
            },
            #logging.getLogger('collect')拿到的logger配置
            'collect': {
                'handlers': ['console', 'collect'],
                'level': 'INFO',
            }
        },
    }
    
    
    # -----------
    # 用法:拿到俩个logger
    
    logger = logging.getLogger(__name__) #线上正常的日志
    collect_logger = logging.getLogger("collect") #领导说,需要为领导们单独定制领导们看的日志

    ==========================直奔主题版============================

    1、日志级别与配置

    import logging
    
    # 一:日志配置
    logging.basicConfig(
        # 1、日志输出位置:1、终端 2、文件
        # filename='access.log', # 不指定,默认打印到终端
    
        # 2、日志格式
        format='%(asctime)s - %(name)s - %(levelname)s -%(module)s:  %(message)s',
    
        # 3、时间格式
        datefmt='%Y-%m-%d %H:%M:%S %p',
    
        # 4、日志级别
        # critical => 50
        # error => 40
        # warning => 30
        # info => 20
        # debug => 10
        level=30,
    )
    
    # 二:输出日志
    logging.debug('调试debug')
    logging.info('消息info')
    logging.warning('警告warn')
    logging.error('错误error')
    logging.critical('严重critical')
    
    '''
    # 注意下面的root是默认的日志名字
    WARNING:root:警告warn
    ERROR:root:错误error
    CRITICAL:root:严重critical
    '''

    2、日志配置字典

    """
    logging配置
    """
    
    import os
    
    # 1、定义三种日志输出格式,日志中可能用到的格式化串如下
    # %(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用户输出的消息
    
    # 2、强调:其中的%(name)s为getlogger时指定的名字
    standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
                      '[%(levelname)s][%(message)s]'
    
    simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
    
    test_format = '%(asctime)s] %(message)s'
    
    # 3、日志配置字典
    LOGGING_DIC = {
        'version': 1,
        'disable_existing_loggers': False,
        'formatters': {
            'standard': {
                'format': standard_format
            },
            'simple': {
                'format': simple_format
            },
            'test': {
                'format': test_format
            },
        },
        'filters': {},
        'handlers': {
            #打印到终端的日志
            'console': {
                'level': 'DEBUG',
                'class': 'logging.StreamHandler',  # 打印到屏幕
                'formatter': 'simple'
            },
            #打印到文件的日志,收集info及以上的日志
            'default': {
                'level': 'DEBUG',
                'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件,日志轮转
                'formatter': 'standard',
                # 可以定制日志文件路径
                # BASE_DIR = os.path.dirname(os.path.abspath(__file__))  # log文件的目录
                # LOG_PATH = os.path.join(BASE_DIR,'a1.log')
                'filename': 'a1.log',  # 日志文件
                'maxBytes': 1024*1024*5,  # 日志大小 5M
                'backupCount': 5,
                'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文log乱码了
            },
            'other': {
                'level': 'DEBUG',
                'class': 'logging.FileHandler',  # 保存到文件
                'formatter': 'test',
                'filename': 'a2.log',
                'encoding': 'utf-8',
            },
        },
        'loggers': {
            #logging.getLogger(__name__)拿到的logger配置
            '': {
                'handlers': ['default', 'console'],  # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
                'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
                'propagate': False,  # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
            },
            '专门的采集': {
                'handlers': ['other',],
                'level': 'DEBUG',
                'propagate': False,
            },
        },
    }
    日志配置字典LOGGING_DIC

    3、使用

    import settings
    
    # !!!强调!!!
    # 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入
    # from logging import config
    # from logging import getLogger
    
    # 2、也可以使用如下导入
    import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config.
    
    # 3、加载配置
    logging.config.dictConfig(settings.LOGGING_DIC)
    
    # 4、输出日志
    logger1=logging.getLogger('用户交易')
    logger1.info('egon儿子alex转账3亿冥币')
    
    # logger2=logging.getLogger('专门的采集') # 名字传入的必须是'专门的采集',与LOGGING_DIC中的配置唯一对应
    # logger2.debug('专门采集的日志')
    common.py

    十三 re模块

    一:什么是正则?

     正则就是用一些具有特殊含义的符号组合到一起(称为正则表达式)来描述字符或者字符串的方法。或者说:正则就是用来描述一类事物的规则。(在Python中)它内嵌在Python中,并通过 re 模块实现。正则表达式模式被编译成一系列的字节码,然后由用 C 编写的匹配引擎执行。

    生活中处处都是正则:

        比如我们描述:4条腿

          你可能会想到的是四条腿的动物或者桌子,椅子等

        继续描述:4条腿,活的

              就只剩下四条腿的动物这一类了

    二:常用匹配模式(元字符)

    http://blog.csdn.net/yufenghyc/article/details/51078107

    # =================================匹配模式=================================
    #一对一的匹配
    # 'hello'.replace(old,new)
    # 'hello'.find('pattern')
    
    #正则匹配
    import re
    #\w与\W
    print(re.findall('\w','hello egon 123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
    print(re.findall('\W','hello egon 123')) #[' ', ' ']
    
    #\s与\S
    print(re.findall('\s','hello  egon  123')) #[' ', ' ', ' ', ' ']
    print(re.findall('\S','hello  egon  123')) #['h', 'e', 'l', 'l', 'o', 'e', 'g', 'o', 'n', '1', '2', '3']
    
    #\n \t都是空,都可以被\s匹配
    print(re.findall('\s','hello \n egon \t 123')) #[' ', '\n', ' ', ' ', '\t', ' ']
    
    #\n与\t
    print(re.findall(r'\n','hello egon \n123')) #['\n']
    print(re.findall(r'\t','hello egon\t123')) #['\n']
    
    #\d与\D
    print(re.findall('\d','hello egon 123')) #['1', '2', '3']
    print(re.findall('\D','hello egon 123')) #['h', 'e', 'l', 'l', 'o', ' ', 'e', 'g', 'o', 'n', ' ']
    
    #\A与\Z
    print(re.findall('\Ahe','hello egon 123')) #['he'],\A==>^
    print(re.findall('123\Z','hello egon 123')) #['he'],\Z==>$


    指定匹配必须出现在字符串的开头或行的开头。

    \A 
    指定匹配必须出现在字符串的开头(忽略 Multiline 选项)。


    指定匹配必须出现在以下位置:字符串结尾、字符串结尾的 \n 之前或行的结尾。

    \Z 
    指定匹配必须出现在字符串的结尾或字符串结尾的 \n 之前(忽略 Multiline 选项)。

    #^与$
    print(re.findall('^h','hello egon 123')) #['h']
    print(re.findall('3$','hello egon 123')) #['3']
    
    # 重复匹配:| . | * | ? | .* | .*? | + | {n,m} |
    #.
    print(re.findall('a.b','a1b')) #['a1b']
    print(re.findall('a.b','a1b a*b a b aaab')) #['a1b', 'a*b', 'a b', 'aab']
    print(re.findall('a.b','a\nb')) #[]
    print(re.findall('a.b','a\nb',re.S)) #['a\nb']
    print(re.findall('a.b','a\nb',re.DOTALL)) #['a\nb']同上一条意思一样
    
    #*
    print(re.findall('ab*','bbbbbbb')) #[]
    print(re.findall('ab*','a')) #['a']
    print(re.findall('ab*','abbbb')) #['abbbb']
    
    #?
    print(re.findall('ab?','a')) #['a']
    print(re.findall('ab?','abbb')) #['ab']
    #匹配所有包含小数在内的数字
    print(re.findall('\d+\.?\d*',"asdfasdf123as1.13dfa12adsf1asdf3")) #['123', '1.13', '12', '1', '3']
    
    #.*默认为贪婪匹配
    print(re.findall('a.*b','a1b22222222b')) #['a1b22222222b']
    
    #.*?为非贪婪匹配:推荐使用
    print(re.findall('a.*?b','a1b22222222b')) #['a1b']
    
    #+
    print(re.findall('ab+','a')) #[]
    print(re.findall('ab+','abbb')) #['abbb']
    
    #{n,m}
    print(re.findall('ab{2}','abbb')) #['abb']
    print(re.findall('ab{2,4}','abbb')) #['abb']
    print(re.findall('ab{1,}','abbb')) #'ab{1,}' ===> 'ab+'
    print(re.findall('ab{0,}','abbb')) #'ab{0,}' ===> 'ab*'
    
    #[]
    print(re.findall('a[1*-]b','a1b a*b a-b')) #[]内的都为普通字符了,且如果-没有被转意的话,应该放到[]的开头或结尾
    print(re.findall('a[^1*-]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b']
    print(re.findall('a[0-9]b','a1b a*b a-b a=b')) #[]内的^代表的意思是取反,所以结果为['a=b']
    print(re.findall('a[a-z]b','a1b a*b a-b a=b aeb')) #[]内的^代表的意思是取反,所以结果为['a=b']
    print(re.findall('a[a-zA-Z]b','a1b a*b a-b a=b aeb aEb')) #[]内的^代表的意思是取反,所以结果为['a=b']
    
    #\# print(re.findall('a\\c','a\c')) #对于正则来说a\\c确实可以匹配到a\c,但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常
    print(re.findall(r'a\\c','a\c')) #r代表告诉解释器使用rawstring,即原生字符串,把我们正则内的所有符号都当普通字符处理,不要转义
    print(re.findall('a\\\\c','a\c')) #同上面的意思一样,和上面的结果一样都是['a\\c']
    
    #():分组
    print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab']
    print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab
    print(re.findall('(?:ab)+123','ababab123')) #findall的结果不是匹配的全部内容,而是组内的内容,?:可以让结果为匹配的全部内容
    print(re.findall('href="(.*?)"','点击'))#['http://www.baidu.com']
    print(re.findall('href="(?:.*?)"','点击'))#['href="http://www.baidu.com"']
    
    #|
    print(re.findall('compan(?:y|ies)','Too many companies have gone bankrupt, and the next one is my company'))
    # ===========================re模块提供的方法介绍===========================
    import re
    #1
    print(re.findall('e','alex make love') )   #['e', 'e', 'e'],返回所有满足匹配条件的结果,放在列表里
    #2
    print(re.search('e','alex make love').group()) #e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
    
    #3
    print(re.match('e','alex make love'))    #None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match
    
    #4
    print(re.split('[ab]','abcd'))     #['', '', 'cd'],先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割
    
    #5
    print('===>',re.sub('a','A','alex make love')) #===> Alex mAke love,不指定n,默认替换所有
    print('===>',re.sub('a','A','alex make love',1)) #===> Alex make love
    print('===>',re.sub('a','A','alex make love',2)) #===> Alex mAke love
    print('===>',re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','alex make love')) #===> love make alex
    
    print('===>',re.subn('a','A','alex make love')) #===> ('Alex mAke love', 2),结果带有总共替换的个数
    
    
    #6
    obj=re.compile('\d{2}')
    
    print(obj.search('abc123eeee').group()) #12
    print(obj.findall('abc123eeee')) #['12'],重用了obj
    import re
    print(re.findall("<(?P\w+)>\w+","

    hello

    ")) #['h1'] print(re.search("<(?P\w+)>\w+","

    hello

    ").group()) #

    hello

    print(re.search("<(?P\w+)>\w+","

    hello

    ").groupdict()) #

    hello

    print(re.search(r"<(\w+)>\w+","

    hello

    ").group()) print(re.search(r"<(\w+)>\w+","

    hello

    ").group())
    补充一
    #补充二
    import re

    #使用|,先匹配的先生效,|左边是匹配小数,而findall最终结果是查看分组,所有即使匹配成功小数也不会存入结果
    #而不是小数时,就去匹配(-?\d+),匹配到的自然就是,非小数的数,在此处即整数
    #
    print(re.findall(r"-?\d+\.\d*|(-?\d+)","1-2*(60+(-40.35/5)-(-4*3))")) #找出所有整数['1', '-2', '60', '', '5', '-4', '3']

    #找到所有数字:
    print(re.findall('\D?(\-?\d+\.?\d*)',"1-2*(60+(-40.35/5)-(-4*3))")) # ['1','2','60','-40.35','5','-4','3']

    #计算器作业参考:http://www.cnblogs.com/wupeiqi/articles/4949995.html
    expression='1-2*((60+2*(-3-40.0/5)*(9-2*5/3+7/3*99/4*2998+10*568/14))-(-4*3)/(16-3*2))'
    
    content=re.search('\(([\-\+\*\/]*\d+\.?\d*)+\)',expression).group() #(-3-40.0/5)
    #为何同样的表达式search与findall却有不同结果:
    print(re.search('\(([\+\-\*\/]*\d+\.?\d*)+\)',"1-12*(60+(-40.35/5)-(-4*3))").group()) #(-40.35/5)
    print(re.findall('\(([\+\-\*\/]*\d+\.?\d*)+\)',"1-12*(60+(-40.35/5)-(-4*3))")) #['/5', '*3']
    
    #看这个例子:(\d)+相当于(\d)(\d)(\d)(\d)...,是一系列分组
    print(re.search('(\d)+','123').group()) #group的作用是将所有组拼接到一起显示出来
    print(re.findall('(\d)+','123')) #findall结果是组内的结果,且是最后一个组的结果
    search与findall
    #_*_coding:utf-8_*_
    __author__ = 'Linhaifeng'
    #在线调试工具:tool.oschina.net/regex/#
    import re
    
    s='''
    http://www.baidu.com
    egon@oldboyedu.com
    你好
    010-3141
    '''
    
    #最常规匹配
    # content='Hello 123 456 World_This is a Regex Demo'
    # res=re.match('Hello\s\d\d\d\s\d{3}\s\w{10}.*Demo',content)
    # print(res)
    # print(res.group())
    # print(res.span())
    
    #泛匹配
    # content='Hello 123 456 World_This is a Regex Demo'
    # res=re.match('^Hello.*Demo',content)
    # print(res.group())
    
    
    #匹配目标,获得指定数据
    
    # content='Hello 123 456 World_This is a Regex Demo'
    # res=re.match('^Hello\s(\d+)\s(\d+)\s.*Demo',content)
    # print(res.group()) #取所有匹配的内容
    # print(res.group(1)) #取匹配的第一个括号内的内容
    # print(res.group(2)) #去陪陪的第二个括号内的内容
    
    
    
    #贪婪匹配:.*代表匹配尽可能多的字符
    # import re
    # content='Hello 123 456 World_This is a Regex Demo'
    #
    # res=re.match('^He.*(\d+).*Demo$',content)
    # print(res.group(1)) #只打印6,因为.*会尽可能多的匹配,然后后面跟至少一个数字
    
    
    #非贪婪匹配:?匹配尽可能少的字符
    # import re
    # content='Hello 123 456 World_This is a Regex Demo'
    #
    # res=re.match('^He.*?(\d+).*Demo$',content)
    # print(res.group(1)) #只打印6,因为.*会尽可能多的匹配,然后后面跟至少一个数字
    
    
    #匹配模式:.不能匹配换行符
    content='''Hello 123456 World_This
    is a Regex Demo
    '''
    # res=re.match('He.*?(\d+).*?Demo$',content)
    # print(res) #输出None
    
    # res=re.match('He.*?(\d+).*?Demo$',content,re.S) #re.S让.可以匹配换行符
    # print(res)
    # print(res.group(1))
    
    
    #转义:\
    
    # content='price is $5.00'
    # res=re.match('price is $5.00',content)
    # print(res)
    #
    # res=re.match('price is \$5\.00',content)
    # print(res)
    
    
    #总结:尽量精简,详细的如下
        # 尽量使用泛匹配模式.*
        # 尽量使用非贪婪模式:.*?
        # 使用括号得到匹配目标:用group(n)去取得结果
        # 有换行符就用re.S:修改模式
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    #re.search:会扫描整个字符串,不会从头开始,找到第一个匹配的结果就会返回
    
    # import re
    # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings'
    #
    # res=re.match('Hello.*?(\d+).*?Demo',content)
    # print(res) #输出结果为None
    
    #
    # import re
    # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings'
    #
    # res=re.search('Hello.*?(\d+).*?Demo',content) #
    # print(res.group(1)) #输出结果为
    
    
    
    #re.search:只要一个结果,匹配演练,
    import re
    content='''
    
    
    1
    ',content) # print(res.group(1)) #re.findall:找到符合条件的所有结果 # res=re.findall('',content) # for i in res: # print(i) #re.sub:字符串替换 import re content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # content=re.sub('\d+','',content) # print(content) #用\1取得第一个括号的内容 #用法:将123与456换位置 # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # # content=re.sub('(Extra.*?)(\d+)(\s)(\d+)(.*?strings)',r'\1\4\3\2\5',content) # content=re.sub('(\d+)(\s)(\d+)',r'\3\2\1',content) # print(content) # import re # content='Extra strings Hello 123 456 World_This is a Regex Demo Extra strings' # # res=re.search('Extra.*?(\d+).*strings',content) # print(res.group(1)) # import requests,re # respone=requests.get('https://book.douban.com/').text # print(respone) # print('======'*1000) # print('======'*1000) # print('======'*1000) # print('======'*1000) # res=re.findall('.*?more-meta.*?author">(.*?)(.*?)(.*?)',respone,re.S) # # res=re.findall('(.*?)(.*?)(.*?).*?',respone,re.S) # # # for i in res: # print('%s %s %s %s' %(i[0].strip(),i[1].strip(),i[2].strip(),i[3].strip()))

    作业:

    import re
    
    # 1、匹配密码,密码必须是由6位数字与字母组成,并且不能是纯数字也不能是纯字母
    # 1.1 知识点:# ?!pattern,表示在没有配到pattern的字符串的前提下,再进行后续的正则表达式匹配,后续匹配仍然从被匹配字符串的头开始
    
    # 1.2 答案:
    print(re.search("(?!^[0-9]+$)(?!^[a-zA-Z]+$)^[0-9A-Za-z]{6}$","123asf").group())  # 123asf
    
    # 1.3 解释:
    # 上述正则的意思为:在匹配(?!^[0-9]+$)以及(?!^[a-zA-Z]+$)过后,如果字符串成功后在从头去匹配(?!^[a-zA-Z]+$),最终匹配完。
    
    
    # 2、匹配密码,密码强度:强,必须包含大写,小写和数字,和特殊字符(!,@,#,%,&),且大于6位
    # 2.1 知识点:# ?=pattern,表示在配到pattern的字符串的前提下,再进行后续的正则表达式匹配,后续匹配仍然从被匹配字符串的头开始
    
    # 2.2 答案:
    # while True:
    #     pwd = input("please your password: ").strip()  # 比如输入:Aa3@adf123
    #     pwd_pattern= re.compile("(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[!@#%&])^([a-zA-Z0-9!@#%&]){6,}$")
    #     if pwd_pattern.search(pwd) is None:
    #         print("密码强度不够")
    #     else:
    #         break
    
    # 2.3 解释:
    # 上述正则表达式的意思:
    #(1)首先是(?=.*[A-Z])匹配,.*表示密码中可以包含多个字符,[A-Z]代表密码中需要包含至少一个大写字母,注意一定不要去掉.*写成(?=[A-Z]),那样表示密码只能由一个字符组成,该字符是大写字母
    #(2)其次是(?=.*[a-z])匹配,同上,确保密码中必须至少有一个小写字母
    #(3)然后是(?=.*[0-9])匹配,同上,确保密码中必须至少有一个数字
    #(4)然后是(?=.*[!@#%&])匹配,同上,,确保密码中必须至少有一个特殊符号!@#%&
    
    #(5)最后是^([a-zA-Z0-9!@#%&]){6,}$,确保密码是由[a-zA-Z0-9!@#%&]字符构成,至少有6位
    
    
    # 3、匹配email
    # print(re.findall("(?:[a-zA-Z0-9]+)@(?:[0-9a-zA-Z]+).com","18611323113@163.com xxx@qq.com"))
    
    # 4、匹配身份证
    # your_id=input(">>: ").strip()
    # print(re.findall("^([0-9]){17}([0-9]|X)$",your_id)) # 17个数字组成,最后一个字符可以是数字或X
    
    # 5、匹配用户名,包含字母或者数字,且8位
    # print(re.findall("^[0-9a-zA-Z]{8}$","egonlinh"))
    
    # 5.1、要求输入的内容只能是汉字
    # name=input('>>: ').strip()
    # print(re.search(r'[\u4E00-\u9fa5]+',name))
    
    # 6、取出字符串里的数字
    # print(re.findall(r'\d+(?:\.\d+)?', 'sww123kw11.333e2lkd'))
    
    # 7、取出所有负整数
    # print(re.findall(r'-\d+', '-12,3,54,-13.11,64,-9'))  # 错误答案
    # print(re.findall(r'(?!-\d+\.\d+)-\d+', '-12,3,54,-13.11,64,-9'))  # 正确答案
    
    # 8、所有数字
    # print(re.findall(r'\-?\d+(?:\.\d+)?', '-12.9,3.92,54.11,64,89,-9,-45.2'))
    
    # 9、所有负数
    # print(re.findall(r'\-\d+(?:\.\d+)?', '-12.9,3.92,54.11,64,89,-9,-45.2'))
    
    # 10、所有的非负浮点数
    print(re.findall(r'\d+\.\d+', '-12.9,3.92,54.11,64,89,-9,-45.2'))
    
    # 11、
    msg = """
    中文名 贝拉克·侯赛因·奥巴马 
    外文名 Barack Hussein Obama II 
    别名 欧巴马 
    性 别 男
    国籍 美国 
    民 族 德裔族 
    出生地 美国夏威夷州檀香山 
    出生日期 1961年8月4日 
    职 业政治家、律师、总统 
    毕业院校 哥伦比亚大学,哈佛大学 
    信 仰新教 
    主要成就 1996年伊利诺伊州参议员 
    主要成就 美国第56届、57届总统 2009年诺贝尔和平奖获得者 时代周刊年度风云人物2008、2011 任期内清除本·拉登 
    代表作品 《我相信变革》《我父亲的梦想》《无畏的希望》 
    所属政党美国民主党 
    血 型 AB型 
    学 院西方学院 
    妻 子 米歇尔·拉沃恩·奥巴马 
    
    """
    #外文名
    print(re.findall("外文名 (.*)",msg))
    
    #出生日期
    print(re.findall('出生日期 (\d{4})年(\d+)月(\d+)日',msg))
    
    #妻子姓名
    print(re.findall('妻 子 (\S+)',msg))

    补充:

    推荐阅读:

    下述表达式都是断言,不占用宽度

        前面有,正向后发(?<=exp),放前面;

        后面有,正向先行(?=exp),放后面;

        前面无,反向后发(?

        后面无,反向先行(?!exp),放后面。

     例如

    re.findall("egon(?=100|N)(?=N)N123","egonN123")  # ['egonN123']
    
    # 位置:   0    1    2    3    4    5    6     7
    # 字符串:e    g    o    n    N    1    2    3
    
    
    # 分析:
    # 步骤1、正则表达式egon匹配到了字符串的位置3
    
    然后连续进行两次断言匹配
    # 步骤2、(?=100|N)从位置3作为起始匹配位置4的字符是否100或者N
    # 步骤3、2成功后,继续匹配(?=N),因为?=patter不会吃字符,所以此时会重新回到步骤1所在位置3,然后继续匹配,匹配成功
    
    # 步骤4、从位置3开始匹配N123
    
    
    # 思考下述输出结果,为何会不同???:
    re.findall("egon(?=100|N)(?=N)N123","egonN123")
    re.findall("egon(?=100|N)(?=N)123","egonN123")

     

    介绍

    (pattern) : 匹配 pattern 并获取这一匹配,所获取的匹配可以从产生的 Matches 集合得到。
    (?:pattern) :匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。
    (?=pattern) :正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

    共同点

    (?:pattern) 与 (?=pattern)都匹配pattern,但不会把pattern结果放到Matches的集合中,即Matcher.group()不会匹配到(?;pattern)与(?=pattern)

    区别

      • (?:pattern) 匹配得到的结果包含pattern,(?=pattern) 则不包含。如:
        对字符串:"industry abc"的匹配结果:
        industr(?:y|ies) ---> "industry"
        industr(?=y|ies) ---> "industr"

        是否消耗字符
        (?:pattern) 消耗字符,下一字符匹配会从已匹配后的位置开始。
        (?=pattern) 不消耗字符,下一字符匹配会从预查之前的位置开始。
        即后者只预查,不移动匹配指针。如: