第十六章:内置模块(re、hashlib、subprocess、logging)

正则表达式

官方定义:正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符、及这些特定字符的组合,组成一个 “规则字符串”,这个 “规则字符串” 用来表达对字符串的一种过滤逻辑。

正则表达式是一门独立的技术 ,所有编程语言都可以使用。

它的作用可以简单的概括为:利用一些特殊符号(也可以直接写需要查找的具体字符)的组合产生一些特殊的含义然后去字符串中筛选出符合条件的数据,即:筛选数据(匹配数据)。

判断手机号是否合法

#re 模块实现
import re
phone_number = input('please input your phone number : ')
if re.match('^(13|14|15|18)[0-9]{9}$',phone_number):
        print('是合法的手机号码')
else:
        print('不是合法的手机号码')

字符组

在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用 [] 表示
字符分为很多类,比如数字、字母、标点等等。
假如你现在要求一个位置 " 只能出现一个数字 ",那么这个位置上的字符只能是 0、1、2...9 这 10 个数之一。

字符组 描述
[0123456789] 匹配 0 到 9 任意一个数(全写)
[0-9] 匹配 0 到 9 任意一个数(缩写)
[a-z] 匹配 26 个小写英文字母
[A-Z] 匹配 26 个大写英文字母
[0-9a-zA-Z] 匹配数字或者小写字母或者大写字母

字符

元字符 匹配内容
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线 (word)
\s 匹配任意的空白符 (space)
\d 匹配数字 (digit)
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示一个组
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符

量词

量词 用法说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
重复 n 次
重复 n 次或更多次
重复 n 到 m 次

.*? 的用法

合在一起就是 取尽量少 的任意字符,一般不会这么单独写,大多用在:(.*?x)取前面任意长度的字符,直到一个 x 出现的时候

关键字符 用法说明
. 是任意字符
* 是取 0 至 无限长度
? 非贪婪模式

其他重要的字符

字符 用法说明
\ 转义符
{1,2}匹配 1 到 2 次任意字符

贪婪匹配

贪婪格式 用法说明
<.*> 默认为贪婪匹配模式,会匹配尽量长的字符串
<.*?> 加上 ?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串

几个常用的非贪婪匹配(Pattern)

格式 用法
*? 重复任意次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
?? 重复0次或1次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n次以上,但尽可能少重复

re 模块

三个非常重要的方法:findall、search、match

findall(找所有)

返回所有满足匹配条件的结果,放在列表里

import re


ret = re.findall('a','eva egon yuan')
print(ret)  # ['a', 'a']

ret = re.findall('[a-z]+','eva egon yuan')
print(ret)  # ['eva', 'egon', 'yuan']

获取式子中的整数

# 获取整数
ret = re.findall(r"\d+\.\d+|(\d+)", "1-2*(60+(-40.35/5)-(-4*3))")
print(ret)  # ['1', '2', '60', '', '5', '4', '3']
ret.remove('')
print(ret)  # ['1', '2', '60', '5', '4', '3']

search(找一个)

从前往后,找到一个就返回,返回的变量需要调用 group 才能拿到结果
如果没有找到,那么返回 None,调用 group 会报错

# search
ret = re.search('a', 'eva egon yuan').group() #当不使用 group() 调用时,返回的是一个结果的对象
print(ret)  # a

ret = re.search('a', 'eva egon yuan')
print(ret)  # <re.Match object; span=(2, 3), match='a'>

# 没有找到值  会报错
# ret = re.search('j', 'eva egon yuan').group()
# print(ret)  # AttributeError: 'NoneType' object has no attribute 'group'

# search 的一般用法
ret = re.search('a', 'eva egon yuan')
if ret:
    print(ret.group())  # a

search 结合分组的用法

ret = re.search('^[1-9](\d{14})(\d{2}[0-9x])?$','110105199912122277')
print(ret.group())  # 110105199912122277
print(ret.group(1))  # 10105199912122  取出第一组
print(ret.group(2))  # 277  取出第二组

分组命名

# 可以在分组中利用?<name>的形式给分组起名字
# 获取的匹配结果可以直接用group('名字')拿到对应的值
ret = re.search("<(?P<tag_name>\w+)>\w+</(?P=tag_name)>", "<h1>hello</h1>")
print(ret.group())  # <h1>hello</h1>
print(ret.group(1)) # h1
print(ret.group('tag_name'))    # h1

ret = re.search(r"<(\w+)>\w+</\1>", "<h1>hello</h1>")
# 如果不给组起名字,也可以用\序号来找到对应的组,表示要找的内容和前面的组内容一致
# 获取的匹配结果可以直接用group(序号)拿到对应的值
print(ret.group(1)) # h1
print(ret.group())  # <h1>hello</h1>

match(从头开始找一个)

用法 search 基本一致
match 是从头开始匹配,如果正则规则从头开始可以匹配上,就返回一个变量。
匹配的内容需要用 group 才能显示,如果没匹配上,就返回 None,调用 group 时会报错

# match
ret = re.match('a','eva egon,yuan') #没有匹配到
if ret:
    print(ret.group())

ret = re.match('e','eva egon,yuan') #匹配到了
if ret:
    print(ret.group())  # e

ret = re.match('[a-z]','eva egon,yuan') #匹配到了
if ret:
    print(ret.group())  # e

hashlib 加密模块

# 加密算法基本操作

# 1.选择加密算法
md5 = hashlib.md5()
# 2.传入明文数据
md5.update(b'hello')
# 3.获取加密密文
res = md5.hexdigest()
print(res)  # 5d41402abc4b2a76b9719d911017c592


# 密码加盐
def hash_salt_pwad(pawd):
    obj = hashlib.md5(b'www.123.con')
    obj.update(pawd.encode('utf-8'))
    return obj.hexdigest()

ret = hash_salt_pwad('password_1231')
print(ret)  # 080a3053fc4d9c69304e87b900784ba5

subprocess 模块

import subprocess

res = subprocess.Popen('ping www.baidu.com', shell=True,
                        stdin=subprocess.PIPE,  # 输入命令
                        stdout=subprocess.PIPE,  # 输出结果
                        stderr=subprocess.PIPE  # 表示当命令不存在的时候,把结果吸入到 stderr 管道
                       )


print('正确结果', res.stdout.read().decode('gbk'))  # 获取操作系统执行命令之后的正确结果
print('错误结果', res.stderr)  # 获取操作系统执行命令之后的错误结果

logging 日志模块

日志级别

日志信息只显示了大于等于 WARNING 级别的日志,这说明默认的日志级别设置为 WARNING

import logging

logging.debug('这是⼀个debug级别的⽇志信息')
logging.info('这是⼀个info级别的⽇志信息')
logging.warning('这是⼀个warning级别的⽇志信息')
logging.error('这是⼀个error级别的⽇志信息')
logging.critical('这是⼀个critical级别的⽇志信息')


# WARNING:root:这是⼀个warning级别的⽇志信息
# ERROR:root:这是⼀个error级别的⽇志信息
# CRITICAL:root:这是⼀个critical级别的⽇志信息

logging 的使用模板

# 定义显示格式
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'

# 自定义文件路径
LOG_DIR = os.path.join(BASE_DIR, 'log')
if not os.path.isdir(LOG_DIR):
    os.mkdir(LOG_DIR)
LOGFILE_PATH = os.path.join(LOG_DIR, 'ATM.log')

# 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',  # 保存到文件
            'class': 'logging.handlers.TimedRotatingFileHandler',  # 按自然天进行分割,保存到文件
            'when': 'midnight',
            'formatter': 'standard',
            'filename': LOGFILE_PATH,  # 日志文件
            # 'maxBytes': 1024 * 1024 * 5,  # 日志大小 5M
            'backupCount': 15,
            'encoding': 'utf-8',  # 日志文件的编码,再也不用担心中文 log 乱码了
        },
    },
    'loggers': {
        # logging.getLogger(__name__)拿到的 logger 配置
        '': {
            'handlers': ['default'],  # 这里把上面定义的两个 handler 都加上,即 log 数据既写入文件又打印到屏幕
            'level': 'DEBUG',
            'propagate': True,  # 向上(更高level的logger)传递
        },  # 当键不存在的情况下 (key设为空字符串)默认都会使用该k:v配置
    },
}

def get_logger(msg):
    logging.config.dictConfig(LOGGING_DIC)  # 自动加载字典中的配置
    logger1 = logging.getLogger(msg)
    return logger1

logger = get_logger('管理员模块')
logger.error(f'管理员{admin_name}冻结了{lock_username}账户')
posted @ 2022-11-01 21:47  亦双弓  阅读(56)  评论(0)    收藏  举报