一 time与datetime与calendar模块

在Python中,通常有这几种方式来表示时间:

  • 时间戳(timestamp):通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量。我们运行“type(time.time())”,返回的是float类型。
  • 格式化的时间字符串(Format String)
  • 结构化的时间(struct_time):struct_time元组共有9个元素共九个元素:(年,月,日,时,分,秒,一年中第几周,一年中第几天,夏令时)

time 模块

import time
#---我们先以当前时间为准,让大家快速认识三种形式的时间
print(time.time()) # 时间戳:1487130156.419527
print(time.strftime("%Y-%m-%d %X")) #格式化的时间字符串:'2017-02-15 11:40:53'
print(time.sleep(1),'延迟1s显示')  #延迟线程运行

print(time.localtime()) #本地时区的struct_time
print(time.gmtime())    #UTC时区的struct_time
时间戳(timestamp):time.time()
延迟线程的运行:time.sleep(secs)
(指定时间戳下的)当前时区时间:time.localtime([secs])
(指定时间戳下的)格林威治时间:time.gmtime([secs])
(指定时间元组下的)格式化时间:time.strftime(fmt[,tupletime])
%y 两位数的年份表示(00-99)
%Y 四位数的年份表示(000-9999)
%m 月份(01-12)
%d 月内中的一天(0-31)
%H 24小时制小时数(0-23)
%I 12小时制小时数(01-12)
%M 分钟数(00=59)
%S 秒(00-59)
%a 本地简化星期名称
%A 本地完整星期名称
%b 本地简化的月份名称
%B 本地完整的月份名称
%c 本地相应的日期表示和时间表示
%j 年内的一天(001-366)
%p 本地A.M.或P.M.的等价符
%U 一年中的星期数(00-53)星期天为星期的开始
%w 星期(0-6),星期天为星期的开始
%W 一年中的星期数(00-53)星期一为星期的开始
%x 本地相应的日期表示
%X 本地相应的时间表示
%Z 当前时区的名称
%% %号本身

其中计算机认识的时间只能是’时间戳’格式,而程序员可处理的或者说人类能看懂的时间有: ‘格式化的时间字符串’,’结构化的时间’ ,于是有了下图的转换关系

#--------------------------按图1转换时间
# localtime([secs])
# 将一个时间戳转换为当前时区的struct_time。secs参数未提供,则以当前时间为准。
# print(time.time())  #1557728037.8418806
time.localtime()
time.localtime(1557728037.8418806)

# gmtime([secs]) 和localtime()方法类似,gmtime()方法是将一个时间戳转换为UTC时区(0时区)的struct_time。

# mktime(t) : 将一个struct_time转化为时间戳。
print(time.mktime(time.localtime())) #1557728277.0


# strftime(format[, t]) : 把一个代表时间的元组或者struct_time(如由time.localtime()和
# time.gmtime()返回)转化为格式化的时间字符串。如果t未指定,将传入time.localtime()。如果元组中任何一个
# 元素越界,ValueError的错误将会被抛出。
print(time.strftime("%Y-%m-%d %X", time.localtime())) #2019-05-13 14:20:05

# time.strptime(string[, format])
# 把一个格式化时间字符串转化为struct_time。实际上它和strftime()是逆操作。
print(time.strptime('2019-05-13 14:20:05', '%Y-%m-%d %X'))
#time.struct_time(tm_year=2019, tm_mon=5, tm_mday=13, tm_hour=14, tm_min=20, tm_sec=5, tm_wday=0, tm_yday=133, tm_isdst=-1)
#在这个函数中,format默认为:"%a %b %d %H:%M:%S %Y"。

#--------------------------按图2转换时间
# asctime([t]) : 把一个表示时间的元组或者struct_time表示为这种形式:'Sun Jun 20 23:21:05 1993'。
# 如果没有参数,将会将time.localtime()作为参数传入。
print(time.asctime())#Sun Sep 11 00:43:43 2016

# ctime([secs]) : 把一个时间戳(按秒计算的浮点数)转化为time.asctime()的形式。如果参数未给或者为
# None的时候,将会默认time.time()为参数。它的作用相当于time.asctime(time.localtime(secs))。
print(time.ctime())  # Sun Sep 11 00:46:38 2016
print(time.ctime(time.time()))  # Sun Sep 11 00:46:38 2016
#--------------------------其他用法
2 # sleep(secs)
3 # 线程推迟指定的时间运行,单位为秒。

datatime可以运算的时间

#时间加减
import datetime

# print(datetime.datetime.now()) #返回当前时间 2019-05-13 14:27:59.947853
# print(datetime.date.fromtimestamp(time.time()))  # 时间戳直接转成日期格式 2019-05-13

# print(datetime.datetime.now())
# print(datetime.datetime.now() + datetime.timedelta(3)) #当前时间 +3天
# print(datetime.datetime.now() + datetime.timedelta(-3)) #当前时间-3天
# print(datetime.datetime.now() + datetime.timedelta(hours=3)) #当前时间+3小时
# print(datetime.datetime.now() + datetime.timedelta(minutes=30)) #当前时间+30分


# c_time  = datetime.datetime.now()
# print(c_time.replace(minute=3,hour=2)) #时间替换
当前时间:datetime.datetime.now()
昨天:datetime.datetime.now() + datetime.timedelta(days=-1)
修改时间:datatime_obj.replace([...])
格式化时间戳:datetime.date.fromtimestamp(timestamp)

calendar日历模块

import calendar
# 判断闰年
print(calendar.isleap(2000))
# 查看某年某月日历
print(calendar.month(2008, 8))
# 查看某年某月起始星期与当月天数
print(calendar.monthrange(2019, 4))
# 查看某年某月某日是星期几
print(calendar.weekday(2019, 4, 1))
判断闰年:calendar.isleap(year)
查看某年某月日历:calendar.month(year, mouth)
查看某年某月起始星期与当月天数:calendar.monthrange(year, mouth)
查看某年某月某日是星期几:calendar.weekday(year, month, day)
# 注:0代表星期一

二 sys系统

import sys

print(0)
sys.exit(0)   #退出运行
print(123)

print(sys.version)  # 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45)\
                    # [MSC v.1900 32 bit (Intel)]
print(sys.maxsize)  #2147483647   最大intprint(sys.platform) #win32
sys.argv           命令行参数List,第一个元素是程序本身路径
sys.exit(n)        退出程序,正常退出时exit(0)
sys.version        获取Python解释程序的版本信息
sys.maxint         最大的Int值(sys.maxsize|sys.maxint)
sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
sys.platform       返回操作系统平台名称
命令行参数List,第一个元素是程序本身路径:sys.argv
退出程序,正常退出时exit(0):sys.exit(n) 
获取Python解释程序的版本信息:sys.version
最大int值:sys.maxsize | sys.maxint
环境变量:sys.path
操作系统平台名称:sys.platform
# 可以实现py文件作为脚本文件执行,实现外部往内部传参
def copy(old_file, new_file):
    print('复制%s操作成%s' % (old_file, new_file))
def move(old_file, new_file):
    print('移动%s操作成%s' % (old_file, new_file))

method_map = {
    'copy': copy,
    'move': move
}
if len(sys.argv) > 3:
    cmd = sys.argv[1]
    old_file = sys.argv[2]
    new_file = sys.argv[3]

    if cmd in method_map:
        method_map[cmd](old_file, new_file)
    else:
        print('该功能暂未提供')
# 启动cmd命令行,用python解释器直接执行python文件,传入指定的参数

三 os操作系统

os 操作系统

生成单级目录:os.mkdir('dirname')
生成多层目录:os.makedirs('dirname1/.../dirnamen2')
重命名:os.rename("oldname","newname") 
工作目录:os.getcwd()
删除单层空目录:os.rmdir('dirname')
移除多层空目录:os.removedirs('dirname1/.../dirnamen') 
列举目录下所有资源:os.listdir('dirname')
路径分隔符:os.sep
行终止符:os.linesep
文件分隔符:os.pathsep
操作系统名:os.name
操作系统环境变量:os.environ
执行shell脚本:os.system() 
生成单级目录:os.mkdir('dirname')
列举目录下所有资源:os.listdir('dirname')
重命名:os.rename("oldname","newname")

import os
# os.mkdir('a')
# os.makedirs('a/b/c')
# os.rename("a", "b")

os path 系统路径操作

执行文件的当前路径:__file__
返回path规范化的绝对路径:os.path.abspath(path)  
将path分割成目录和文件名二元组返回:os.path.split(path)  
上一级目录:os.path.dirname(path) 
最后一级名称:os.path.basename(path)
指定路径是否存在:os.path.exists(path)
是否是绝对路径:os.path.isabs(path)
是否是文件:os.path.isfile(path)
是否是路径:os.path.isdir(path) 
路径拼接:os.path.join(path1[, path2[, ...]])
最后存取时间:os.path.getatime(path)
最后修改时间:os.path.getmtime(path)
目标大小:os.path.getsize(path)
normcase函数
在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
>>> os.path.normcase('c:/windows\\system32\\')   
'c:\\windows\\system32\\'   

normpath函数
规范化路径,如..和/
>>> os.path.normpath('c://windows\\System32\\../Temp/')   
'c:\\windows\\Temp'   

>>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1

四 random随机数

(0, 1):random.random()
[1, 10]:random.randint(1, 10)
[1, 10):random.randrange(1, 10)
(1, 10):random.uniform(1, 10)
单例集合随机选择1个:random.choice(item)
单例集合随机选择n个:random.sample(item, n)
洗牌单列集合:random.shuffle(item)
import random

print(random.random())#(0,1)----float    大于0且小于1之间的小数

print(random.randint(1,3))  #[1,3]    大于等于1且小于等于3之间的整数

print(random.randrange(1,3)) #[1,3)    大于等于1且小于3之间的整数

print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5]

print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合

print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716 


item=[1,3,5,7,9]
random.shuffle(item) #打乱item的顺序,相当于"洗牌"
print(item)
import random
print(random)

# for i in range(10):
#     print(random.random())  # (0, 1)


# for i in range(10):
#     print(random.randint(1, 10))  # [1, 10]

# for i in range(10):
#     print(random.randrange(1, 10))  # [1, 9]  [1, 10)

for i in range(10):
    print('%.2f' % random.uniform(1, 10))  # 小数:(1, 10)
ls = [1, 2, 3, 4, 5]
print(random.shuffle(ls))
print(ls)

print(random.choice(ls))

print(random.sample(ls, 3))

验证码
法1:

def get_code(count):
    code = ""
    # 能产生大小写字母与数字
    # 进行字符串拼接
    for i in range(count):
        c1 = chr(random.randint(65, 90))
        c2 = chr(random.randint(97, 122))
        c3 = str(random.randint(0, 9))
        code += random.choice([c1, c2, c3])
    return code

print(get_code(18))

法2:

def get_code(count):
    code = ""
    # 能产生大小写字母与数字
    # 进行字符串拼接
    for i in range(count):
        r = random.choice([1, 2, 3])
        if r == 1:
            c = chr(random.randint(65, 90))
        elif r == 2:
            c = chr(random.randint(97, 122))
        else:
            c = str(random.randint(0, 9))
        code += c
    return code
print(get_code(18))

法3:

def get_code(count):
    target = "1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
    code_list = random.sample(target, count)
    return ''.join(code_list)

print(get_code(6))

五 序列化json、pickle、shelve

什么是序列化:将对象转化为字符串
什么是反序列化:将字符串转化为对象
为什么要序列化:数据的存储和传输都采用的是字符串类型
序列化的模块:json pickle shelve

json:支持跨语言,用于数据的传输
pickle:支持py的所有数据类型,所有可以将所有py的对象序列化后存储
shelve:支持py的所有数据类型,可以即时存于取

序列化
dump
dumps

反序列化
load
loads

json模块: 用于传输(多语言支持)
什么是json:就是完成文本序列化得到的文本字符串,json字符串具有一定的语法规范

1.支持的数据类型:int float str bool dict list null
2.复杂的json都是由{}与[]嵌套形成的数据
3.json字符串只能有一个根: json_str = '{}{}' | '{}[]' | '[][]' | '1null'  # 报错,都是两个根
4.json中的str类型必须用""包裹(json字符串中的字符串类型不支持'' """""")
# python对象 序列化 json字符串
data = None
res = json.dumps(data)
print(res)

# json字符串 反序列化 python对象
json_str = '3.14'
json_str = 'true'
json_str = 'null'
json_str = '{}'
json_str = '[]'
json_str = '1, null'  # 有误,两个根
# str类型,json只支持""
json_str = "\"abc\""
json_str = '"abc"'
obj = json.loads(json_str)
print(obj, type(obj))

操作文件

# 序列化
obj = {'name': 'Owen', 'age': 17, 'gender': '男'}

with open('a.txt', 'w', encoding='utf-8') as wf:
    json.dump(obj, wf, ensure_ascii=False)
    # json.dump(obj, wf, ensure_ascii=False)
    # wf.write('123')
    # wf.write('456')

# 反序列化
with open('a.txt', 'r', encoding='utf-8') as rf:
    obj = json.load(rf)
    print(obj)

print(json.load(open('a.txt', 'r', encoding='utf-8')))
注:json模块的序列化与反序列化是一一对应关系

pickle模块:支持所有数据类型

import pickle

# 序列化
obj = {'name': 'Owen', 'age': 17, 'gender': '男'}
res = pickle.dumps(obj)
print(res)

pickle.dump(obj, open('b.txt', 'wb'))


# 反序列化
print(pickle.loads(res))
print(pickle.load(open('b.txt', 'rb')))

shelve模块:支持所有数据类型,即时存取

import shelve
shv_tool = shelve.open('c.shv')

# 序列化
shv_tool['name'] = 'Owen'

# 反序列化
res = shv_tool['name']
print(res)
# 文件通过shelve对象来关闭
shv_tool.close()

# writeback将反序列化到内存的数据,操作后即时同步到文件中
with shelve.open('c.shv', writeback=True) as shv_tool:
    shv_tool['stus'] = ['Bob', 'Tom']
    # print(shv_tool['stus'])

    shv_tool['stus'].append('Jobs')
    print(shv_tool['stus'])

六 shutil 可以操作权限的处理文件模块

高级的 文件、文件夹、压缩包 处理模块

import shutil

# 基于路径的文件复制:
shutil.copyfile('source_file', 'target_file')

# 基于流的文件复制:
with open('source_file', 'rb') as r, open('target_file', 'wb') as w:
    shutil.copyfileobj(r, w)

# 递归删除目标目录
shutil.rmtree('target_folder')

# 文件移动
shutil.remove('old_file', 'new_file')

# 文件夹压缩
# file_name: 压缩后得到的文件名  format:压缩格式  archive_path:要压缩的文件夹路径
shutil.make_archive('file_name', 'format', 'archive_path')

# 文件夹解压
# unpack_file: 解压的文件  unpack_name:解压得到的文件夹名  format:解压格式
shutil.unpack_archive('unpack_file', 'unpack_name', 'format')

七 加密模块

hashlib模块

md5加密:不可逆加密
碰撞认证:用数据再进行一次加密,与原加密结果做匹配

import hashlib

data = '数据'
lock_obj = hashlib.md5(data.encode('utf-8'))  # 生产加密锁对象,传入加密数据
result = lock_obj.hexdigest()  # 获取加密后的加密串
print(result)


# 加盐
# 什么是加盐:在原数据前或后添加一些预定的数据,与原数据一起进行加密
# 为什么要加盐:
# 1.当原数据过于简单,可以对其加盐,提高数据的复杂度
# 2.盐与数据有一定相似度,混淆对真实数据的提取
lock_obj = hashlib.md5()  # 生产锁对象可以添加数据参数也可以省略
lock_obj.update(b'before_salt')
lock_obj.update('要被加密的数据'.encode('utf-8'))
lock_obj.update(b'after_salt')
print(lock_obj.hexdigest())


# 注:要为新数据提供加密,一定要为该数据创建一个加密对象

# 其他算法
lock_obj = hashlib.sha3_256(b'123')
print(lock_obj.hexdigest())
lock_obj = hashlib.sha3_512(b'123')
lock_obj.update(b'salt')
print(lock_obj.hexdigest())

hmac模块

import hmac
# 与hashlib的不同点:生产锁对象时必须提高数据参数
lock_obj = hmac.new(b'')
print(lock_obj.hexdigest())

lock_obj = hmac.new(b'')
lock_obj.update(b'salt')
print(lock_obj.hexdigest())

八 logging模块

logging记录项目日志的模块
记录日志:将项目中产生的一些数据,或是信息,或是错误不再输出到控制台,而是输出到文件中,保存这样信息的文件就称之为日志文件

基本使用

import logging
import sys

# 1.五大级别
logging.debug('debug msg')
logging.info('info msg')
logging.warning('warning msg')
# logging.warn('warning msg')  # 弃用
logging.error('error msg')
logging.critical('critical msg')
logging.fatal('critical msg')  # 同critical
本质上他们使用数字来表示级别的,从高到低分别是10,20,30,40,50

# 2.日志的基本配置
logging.basicConfig(
    # 输出级别
    # level=logging.INFO,
    level=10,

    # 输出位置
    stream=sys.stderr,  # sys.stdout  往控制台输出
    # filename='log/my.log',  # 往文件输出  => 如果需要同时往多个位置输出,需要handles

    # 输出格式
    format='%(asctime)s: %(msg)s',
    datefmt='%H:%M:%S'
)

格式化全部可用名称

%(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模块的四个核心角色

1.Logger    日志生成器 产生日志
2.Filter    日志过滤器  过滤日志
3.Handler   日志处理器 对日志进行格式化,并输出到指定位置(控制台或文件)
4.Formater  处理日志的格式

一条日志完整的生命周期
1.由logger 产生日志 -> 2.交给过滤器判断是否被过滤 -> 3.将日志消息分发给绑定的所有处理器 -> 4处理器按照绑定的格式化对象输出日志

其中 第一步 会先检查日志级别 如果低于设置的级别则不执行

第二步 使用场景不多 需要使用面向对象的技术点 后续用到再讲

第三步 也会检查日志级别,如果得到的日志低于自身的日志级别则不输出

生成器的级别应低于句柄否则给句柄设置级别是没有意义的,

例如  handler设置为20  生成器设置为30 

30以下的日志压根不会产生

第四步 如果不指定格式则按照默认格式

成员组成

import logging

# 1.打印者:自定义的打印者如何配置
log1 = logging.getLogger('logger name')

# 2.输出位置:两个文件输出位置与一个控制台输出位置
hd_a = logging.FileHandler('log/a.log', encoding='utf-8')
hd_cmd = logging.StreamHandler()

# 3.输出格式
fmt1 = logging.Formatter('%(asctime)s 【%(name)s】- %(msg)s')
fmt2 = logging.Formatter('%(asctime)s - %(msg)s')

# 4.打印者添加句柄 - 设置打印者的输出位置
log1.addHandler(hd_a)
log1.addHandler(hd_cmd)

# 5.将格式绑定给输出位置(句柄)
hd_a.setFormatter(fmt1)
hd_cmd.setFormatter(fmt2)

# 6.权限控制
log1.setLevel(logging.DEBUG)  # 打印者规定打印级别
hd_a.setLevel(logging.WARNING)  # 不同输出位置(句柄)再可以二次限定输出级别
hd_cmd.setLevel(logging.DEBUG)  # 不同输出位置(句柄)再可以二次限定输出级别

# 7.不同级别输出信息
log1.debug('debug msg')
log1.info('info msg')
log1.warning('warning msg')
log1.error('error msg')
log1.critical('critical msg')

logging配置文件的项目运用

1.将打印者,句柄,与格式封装成配置信息
2.加载配置信息
3.使用自定义logger,采用的就是配置信息设置的logger

优势:1,2两步是一劳永逸的,后期开发只需要在要记录日志的文件中使用自定义logger

1、配置

LOGGING_DIC = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'o_fmt1': {
            'format': '%(asctime)s 【%(name)s】- %(msg)s'
        },
        'o_fmt2': {
            'format': '%(asctime)s - %(msg)s'
        }
    },
    'filters': {},
    'handlers': {
        'o_hd_file': {
            'level': 'WARNING',
            'class': 'logging.handlers.RotatingFileHandler',  # 保存到文件
            'formatter': 'o_fmt1',
            'filename': 'log/sys.log',
            'encoding': 'utf-8',
            'maxBytes': 1024*1024*5,  # 日志大小 5M
            'backupCount': 5,   # 日志文件最大个数
        },
        'o_hd_cmd': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',  # 打印到控制台
            'formatter': 'o_fmt2'
        }
    },
    'loggers': {
        'o_owen': {
            'level': 'DEBUG',
            'handlers': ['o_hd_file', 'o_hd_cmd']
        },
        'o_zero': {
            'level': 'DEBUG',
            'handlers': ['o_hd_cmd'],
            # 'propagate': True  # 向上传递
        }
    }
}

2、加载配置

import logging.config
logging.config.dictConfig(LOGGING_DIC)

3、使用

log = logging.getLogger('o_zero')
log.critical('信息')

log1 = logging.getLogger('o_owen')
log1.critical('信息')

九 re模块

re:正则,全称正则字符串 - re就是有特殊语法的字符串
re可以将有正则语法的字符串解析为对应的正则对象,用来匹配目标字符串

学习re的目的:1.判断目标字符串是否合法 2.在目标字符串中提取想要的信息(信息匹配规则采用正则)

元字符 描述
\ 将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“\n”匹配\n。“\n”匹配换行符。序列“\”匹配“\”而“(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。
^ 匹配输入字行首。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。
$ 匹配输入行尾。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。
* 匹配前面的子表达式任意次。例如,zo能匹配“z”,也能匹配“zo”以及“zoo”。等价于{0,}。
+ 匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。
{n} n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。
{n,} n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。
{n,m} mn均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o为一组,后三个o为一组。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。
? 匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”。?等价于{0,1}。
? 当该字符紧跟在任何一个其他限制符(,+,?,{n},{n,},{n,m*})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少地匹配所搜索的字符串,而默认的贪婪模式则尽可能多地匹配所搜索的字符串。例如,对于字符串“oooo”,“o+”将尽可能多地匹配“o”,得到结果[“oooo”],而“o+?”将尽可能少地匹配“o”,得到结果 [‘o’, ‘o’, ‘o’, ‘o’]
.点 匹配除“\n”和”\r”之外的任何单个字符。要匹配包括“\n”和”\r”在内的任何字符,请使用像“[\s\S]”的模式。
x|y 匹配x或y。例如,“z|food”能匹配“z”或“food”(此处请谨慎)。“[zf]ood”则匹配“zood”或“food”。
[xyz] 字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。
[^xyz] 负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”任一字符。
[a-z] 字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围; 如果出字符组的开头,则只能表示连字符本身.
[^a-z] 负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。
\b 匹配一个单词的边界,也就是指单词和空格间的位置(即正则表达式的“匹配”有两种概念,一种是匹配字符,一种是匹配位置,这里的\b就是匹配位置的)。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”;“\b1_”可以匹配“1_23”中的“1_”,但不能匹配“21_3”中的“1_”。
\B 匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”
\s 匹配任何不可见字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。
\S 匹配任何可见字符。等价于[^ \f\n\r\t\v]。
\w 匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的”单词”字符使用Unicode字符集。
\W 匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。
\d 匹配一个数字字符。等价于[0-9]。grep 要加上-P,perl正则支持
\D 匹配一个非数字字符。等价于[^0-9]。grep要加上-P,perl正则支持
\n 匹配一个换行符。等价于\x0a和\cJ。
\r 匹配一个回车符。等价于\x0d和\cM。
\t 匹配一个制表符。等价于\x09和\cI。
( ) 将( 和 ) 之间的表达式定义为“组”(group),并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个),它们可以用 \1 到\9 的符号来引用。
(?:pattern) 非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分时很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。
| 将两个匹配条件进行逻辑“或”(Or)运算。例如正则表达式(him|her) 匹配”it belongs to him”和”it belongs to her”,但是不能匹配”it belongs to them.”。注意:这个元字符不是所有的软件都支持的。

单个字符匹配

\w 

\W

 \s

 \S

 \d

 \D

 .

 \r

 \n

 \t

指定匹配范围

a|b|c

[abc]

[^abc]

[a-z]

[a-zA-Z0-9]

注意当 -需要作为普通字符时必须写在最前面或最后面

匹配次数

{a}

{b,}

{a,b}

*  

位置匹配

^

$

\d

\B

贪婪模式

默认情况下+和*将尽可能多的匹配内容

+

*

非贪婪模式

将尽可能少的匹配内容,当?出现在其他的重复次数后面时会将贪婪模式改为非贪婪模式。

?

如

abc.*?

abc.+?

分组

用于单独获取某一部分匹配的内容

(表达式)获取匹配的

(?:表达式) 不获取匹配的

基本使用

import re

r1 = re.findall(r'1', '123abc123')
print(r1)

# re.I不区分大小写匹配
r2 = re.findall(r'a', '123abc123ABC', flags=re.I)
print(r2)

# 1.将 r'\d' 丢给_compile得到可以匹配数字的 正则对象
# 2.正则对象.findall('目标字符串')
r3 = re.findall(r'\d', '123abc123')
print(r3)


re_obj = re.compile(r'\d')  # 将 r'\d' 丢给_compile得到可以匹配数字的 正则对象
r4 = re_obj.findall('123abc123')  # 正则对象.findall('目标字符串')
print(r4)

单个字符

# 一、单个字符语法
# 匹配a
print(re.findall(r'a', '123abc嘿嘿'))  # ['a']

# a或b
print(re.findall(r'a|b', '123abc嘿嘿'))  # ['a', 'b'] 不建议使用
print(re.findall(r'[ab]', '123abc嘿嘿'))  # ['a', 'b'] 建议使用

# 非a非b
print(re.findall(r'[^ab]', '123abc嘿嘿'))  # ['1', '2', '3', 'c', '嘿', '嘿']

# 数字
print(re.findall(r'[0-9]', '12abc嘿嘿12'))  # ['1', '2', '1', '2'] 建议使用
print(re.findall(r'\d', '12abc嘿嘿12'))  # ['1', '2', '1', '2'] 不建议使用

# 字母
print(re.findall(r'[a-zA-Z]', '12abc[嘿嘿ABC'))  # ['a', 'b', 'c', 'A', 'B', 'C']

# 字母数字_常用汉字:\w => 建议使用 [a-zA-Z0-9_]
print(re.findall(r'\w', '12abc[_嘿嘿ABC'))  # ['1', '2', 'a', 'b', 'c', '_', '嘿', '嘿', 'A', 'B', 'C']

# 汉字 [\u4e00-\u9fa5]
print(re.findall(r'[\u4e00-\u9fa5]', '12abc[_嘿嘿ABC'))  # ['嘿', '嘿']

# 空白字符:\s => 建议使用[ \f\n\r\t\v]
print(re.findall(r'\s', ' \f\n\r\t\v'))  # [' ', '\x0c', '\n', '\r', '\t', '\x0b']

# 非\n的任意字符: .
print(re.findall(r'.', ' \f\n\r\t\v*&_.'))  # [' ', '\x0c', '\r', '\t', '\x0b', '*', '&', '_', '.']

# 只想匹配.字符:\.
print(re.findall(r'\.', ' \f\n\r\t\v*&_.'))  # ['.']

# re.S: 让.也能匹配\n,就可以理解为 . 可以匹配所有字符
print(re.findall(r'.', ' \f\n\r\t\v*&_.', flags=re.S))

# 取对立面 \d数字 \D非数字  \w=>\W  \s=>\S
print(re.findall(r'\D', '12abc\f嘿嘿12'))  # ['a', 'b', 'c', '\x0c', '嘿', '嘿']

重复字符语法

# 二、重复字符语法
print(re.findall(r'ab', 'abacbabc'))  # ['ab', 'ab']

# 指定个数: 匹配abb
print(re.findall(r'ab{2}', 'aababbabbb'))  # ['abb', 'abb']

# 贪婪匹配: 尽可能多的匹配
# a0~2个b: a | ab | abb
print(re.findall(r'ab{,2}', 'aababbabbb'))  # ['a', 'ab', 'abb', 'abb']

# a0~n个b:
print(re.findall(r'ab{0,}', 'aababbabbb'))  # ['a', 'ab', 'abb', 'abbb']

# a1~3个b:
print(re.findall(r'ab{1,3}', 'aababbabbb'))  # ['ab', 'abb', 'abbb']

# *: {0,}
print(re.findall(r'ab*', 'aababbabbb'))  # ['a', 'ab', 'abb', 'abbb']
# +: {1,}
print(re.findall(r'ab+', 'aababbabbb'))  # ['ab', 'abb', 'abbb']
# ?: {,1}
print(re.findall(r'ab?', 'aababbabbb'))  # ['a', 'ab', 'ab', 'ab']

# 非贪婪匹配
print(re.findall(r'ab{1,3}?', 'aababbabbb'))  # ['ab', 'ab', 'ab']

# 重点:非贪婪匹配应用场景,一般都是结合有开头与结尾的标识
print(re.findall(r'<.{1,}>', '<a><b>msg</b></a>'))  # ['<a><b>msg</b></a>']
# 匹配标签
print(re.findall(r'<.{1,}?>', '<a><b>msg</b></a>'))  # ['<a>', '<b>', '</b>', '</a>']

# *?: {0,}?
# +?: {1,}?
# ??: {,1}?
print(re.findall(r'<.+?>', '<a><b>msg</b></a>'))  # ['<a>', '<b>', '</b>', '</a>']

分组语法

# 引子
print(re.findall(r'(?:ab){2}', 'abbabab'))  # ['abab']

# findall(): 没有分组情况下,显示匹配的结果;如果有分组,显示分组结果

# 分组:()
# 取消分组:(?:)
# 有名分组:(?P<名字>)

# 案例:
# 匹配链接
print(re.findall(r'www\..+?\.com', 'www.baidu.comabcwww.sina.com'))  # ['www.baidu.com', 'www.sina.com']
# 获取链接的域名:['baidu', 'sina']
print(re.findall(r'www\.(.+?)\.com', 'www.baidu.comabcwww.sina.com'))  # ['baidu', 'sina']

# 分组编号: 从左往右数左(进行分组编号
# [('www.baidu.com', 'baidu', 'com'), ('www.sina.edu', 'sina', 'edu')]
res = re.findall(r'(www\.(.+?)\.(com|edu))', 'www.baidu.comabcwww.sina.edu')
print(res)
print(res[0][1])

# 取消分组:(?:) 应用于,要将一些数据作为整体看待,但由不能产生分组
# [('www.baidu.com', 'baidu'), ('www.sina.edu', 'sina')]
res = re.findall(r'(www\.(.+?)\.(?:com|edu))', 'www.baidu.comabcwww.sina.edu')
print(res)

正则其他方法

#e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
print(re.search('e','alex make love').group())

# match:不是全文匹配,必须从头开始匹配,且只匹配一次
res = re.match(r'(www\.(?P<site_name>.+?)\.(?:com|edu))', 'www.baidu.comwww.sina.edu')
# 可以通过分组号直接取出分组内容
print(res.group(1))
print(res.group(2))
# print(res.group(0), res)  # 匹配的整体

# 有名分组
print(res.group('site_name'))


# split(): 拆分
print('abc def xyz'.split(' '))
print(re.split(r' ', 'abc def xyz'))
print(re.split(r'[,@ ]', 'abc,def@xyz opq'))


# sub(): 替换
res = re.sub(r'good', 'bed', 'good good day a')
print(res)  # bed bed day a

res = re.sub(r'good', 'bed', 'good good day a', count=1)
print(res)  # bed good day a

res = re.sub(r'good day a', '123', 'good day a!!!')
print(res)  # 123!!!

# 结合分组可以完成数据的重组
res = re.sub(r'(good) (day) (a)', r'today is \3 \1 \2', 'good day a!!!')
print(res)  # today is a good day!!!

十 subprocess模块

操作shell命令

用来生成子进程,并可以通过管道连接他们的输入/输出/错误,以及获得他们的返回值。
subprocess提供了一些管理标准流(standard stream)和管道(pipe)的工具,从而在进程间使用文本通信。

import subprocess
order = subprocess.Popen('终端命令', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
suc_res = order.stdout.read().decode('系统默认编码')
err_res = order.stderr.read().decode('系统默认编码')

order = subprocess.run('终端命令', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
suc_res = order.stdout.decode('系统默认编码')
err_res = order.stderr.decode('系统默认编码')

调用subprocess.run(…)是推荐的常用方法,在大多数情况下能满足需求,但如果你可能需要进行一些复杂的与系统的交互的话,你还可以用subprocess.Popen()

十一 configparser模块

操作配置文件

# my.ini
[section1]
option1_1 = value1_1
option1_2 = value1_2

[section2]
option2_1 = value2_1
option2_2 = value2_2
import configparser
parser = configparser.ConfigParser()
# 读
parser.read('my.ini', encoding='utf-8')
# 所有section
print(parser.sections())  
# 某section下所有option
print(parser.options('section_name'))  
# 某section下某option对应的值
print(parser.get('section_name', 'option_name')) 

# 写
parser.set('section_name', 'option_name', 'value')
parser.write(open('my.ini', 'w'))

案例

my.ini
[server]
ip = 192.168.66.88
port = 6666

[client]
user = root
password = root
import configparser

# 1.初始化
parser = configparser.ConfigParser()

# 2.读
parser.read('my.ini', encoding='utf-8')
# section | option | value
sts = parser.sections()
print(sts, type(sts))  # ['server', 'client'] <class 'list'>
ops = parser.options(sts[0])
print(ops)  # ['ip', 'port']
value = parser.get(sts[0], ops[0])
print(value, type(value))
# get=>str getboolean=>bool getfloat=>float getint=>int
print(parser.get('server', 'port'))

# 3.写
parser.read('my.ini', encoding='utf-8')
parser.set('server', 'port', '6666')
parser.write(open('my.ini', 'w'))

十二 xlrd、xlwt模块

            年终报表                
        教学部    市场部    咨询部    总计
Jan-19    10        15        5    30
Feb-19    10        15        5    30
Mar-19    10        15        5    30
Apr-19    10        15        5    30
May-19    10        15        5    30
Jun-19    10        15        5    30
Jul-19    10        15        5    30
Aug-19    10        15        5    30
Sep-19    10        15        5    30
Oct-19    10        15        5    30
Nov-19    10        15        5    30
Dec-19    10        15        5    30

xlrd模块:excel读

import xlrd
# 读取文件
work_book = xlrd.open_workbook("机密数据.xlsx")
# 获取所有所有表格名称
print(work_book.sheet_names())
# 选取一个表
sheet = work_book.sheet_by_index(1)
# 表格名称
print(sheet.name)
# 行数
print(sheet.nrows)
# 列数
print(sheet.ncols)
# 某行全部
print(sheet.row(6))
# 某列全部
print(sheet.col(6))
# 某行列区间
print(sheet.row_slice(6, start_colx=0, end_colx=4))
# 某列行区间
print(sheet.col_slice(3, start_colx=3, end_colx=6))
# 某行类型 | 值
print(sheet.row_types(6), sheet.row_values(6))
# 单元格
print(sheet.cell(6,0).value) # 取值
print(sheet.cell(6,0).ctype) # 取类型
print(sheet.cell_value(6,0)) # 直接取值
print(sheet.row(6)[0])
# 时间格式转换
print(xlrd.xldate_as_datetime(sheet.cell(6, 0).value, 0))

xlwt模块:excel写

import xlwt
# 创建工作簿
work = xlwt.Workbook()
# 创建一个表
sheet = work.add_sheet("员工信息数据")
# 创建一个字体对象
font = xlwt.Font()
font.name = "Times New Roman"  # 字体名称
font.bold = True  # 加粗
font.italic = True  # 斜体
font.underline = True  # 下划线
# 创建一个样式对象
style = xlwt.XFStyle()
style.font = font
keys = ['Owen', 'Zero', 'Egon', 'Liuxx', 'Yhh']
# 写入标题
for k in keys:
    sheet.write(0, keys.index(k), k, style)
# 写入数据
sheet.write(1, 0, 'cool', style)
# 保存至文件
work.save("test.xls")

十三 xml模块

<?xml version="1.0"?>
<data>
    <country name="Liechtenstein">
        <rank updated="yes">2</rank>
        <year>2008</year>
        <gdppc>141100</gdppc>
        <neighbor name="Austria" direction="E"/>
        <neighbor name="Switzerland" direction="W"/>
    </country>
    <country name="Singapore">
        <rank updated="yes">5</rank>
        <year>2011</year>
        <gdppc>59900</gdppc>
        <neighbor name="Malaysia" direction="N"/>
    </country>
    <country name="Panama">
        <rank updated="yes">69</rank>
        <year>2011</year>
        <gdppc>13600</gdppc>
        <neighbor name="Costa Rica" direction="W"/>
        <neighbor name="Colombia" direction="E"/>
    </country>
</data>
import xml.etree.ElementTree as ET
# 读文件
tree = ET.parse("xmltest.xml")
# 根节点
root_ele = tree.getroot()
# 遍历下一级
for ele in root_ele:
    print(ele)

# 全文搜索指定名的子标签
ele.iter("标签名")
# 非全文查找满足条件的第一个子标签
ele.find("标签名")
# 非全文查找满足条件的所有子标签
ele.findall("标签名")

# 标签名
ele.tag
# 标签内容
ele.text
# 标签属性
ele.attrib

# 修改
ele.tag = "新标签名"
ele.text = "新文本"
ele.set("属性名", "新属性值")

# 删除
sup_ele.remove(sub_ele)

# 添加
my_ele=ET.Element('myEle')
my_ele.text = 'new_ele' 
my_ele.attrib = {'name': 'my_ele'}
root.append(my_ele)

# 重新写入硬盘
tree.write("xmltest.xml")
文档更新时间: 2019-05-21 12:08   作者:李延召