常用模块

发布时间 2023-12-28 10:46:59作者: 桃源氏

常用模块

一、random模块

[1]随机小数

(1)默认区间的小数(random

  • 在0和1之间的小数(可以取到0和1)
import random

res = random.random()
print(res)
#运行两次取到不同的值
'''
0.979163945152883
0.3838093323775482
'''

(2)指定区间的小数(uniform

  • 可以指定特定的区间
import random

res = random.uniform(1, 2)
print(res)
#运行两次取到不同的值
'''
1.1766418536839538
1.3282317288927623
'''

[2]随机整数

(1)随机区间整数(randint

  • 特定区间的随机整数
import random

# 取一到十之间的随机整数
res = random.randint(1, 10)
print(res)
#运行两次取到不同的值
'''
    9
    3
'''

(2)随机区间并且可以确定取值的跨度(randrange

import random

#其实就是在range(1 ,10, 2)的结果中取值
import random

for i in range(1, 10, 2):
    print(i, end=' ')
print('\n')

#这里就只能取到1, 3, 5, 7, 9
res = random.randrange(1, 10, 2)
print(res)
'''
    1 3 5 7 9 
    
    1
'''

#其实就是在range(1 ,10, 3)的结果中取值
for i in range(1, 10, 3):
    print(i, end=' ')
print('\n')

#这里就只能取到1, 4, 7
res = random.randrange(1, 10, 3)
print(res)
'''
    1 4 7 
    
    4
''''

[3]随机选择返回

(1)随机返回一个(choice

  • 随机返回一个列表或者元组的值
import random

list_choice = ['Xanadu', 'bridge', 'water', 'farm']
# 会随机返回一个列表里的值
res = random.choice(list_choice)
print(res)
'''
    bridge
    water
'''

(2)随机返回指定的个数(sample

import random

list_choice = ['Xanadu', 'bridge', 'water', 'farm']
# 返回列表里特定数量的值
res = random.sample(list_choice, 2)
print(res)
'''
    ['farm', 'Xanadu']
    ['farm', 'water']
'''

[4]打乱列表顺序(shuffle

import random

old_list = [1, 2, 3, 4, 5, 6]
print(old_list)
#使用shuff打乱列表
random.shuffle(old_list)
#打印处理过列表
print(old_list)
'''
    [1, 2, 3, 4, 5, 6]
    [4, 6, 5, 2, 3, 1]
'''

[5]运用

  • 制作一个可以指定位数的验证码生成器
import random


def random_code(num):
    num = int(num)
    # 定义一个包含随机数字和随机大小写字母的列表
    # 为了让数字和字母尽可能的达到1:1所以加了两个数字的随机元素(主要还是靠随机)
    # chr()函数可以通过数字对应到ascii表中的字符,
    #(97,122)和(65,95)分别是小写字母和大写字母所对应的数字
	captcha_list = [random.randint(0, 9), random.randint(0, 9), chr(random.randint(97, 122)),
                    chr(random.randint(65, 90))]
    code = ''
    #通过所给的数字来决定运行几次循环,确定拼接几位的字符串验证码
    for i in range(num):
        code = code + str(random.choice(captcha_list))
    return code


captcha = random_code("4")
print(captcha)
captcha_input = input("请输入验证码:")
#可以将随机出来的验证码字符串和输入的字符串全部转化为大写字母,以达到不区分大小写的功能
if captcha_input.upper() == captcha.upper():
    print("登录成功!")
else:
    print("验证码错误!")

'''
    9F99
    请输入验证码:9F99
    登录成功!
'''

二、os模块

[1]文件路径相关(os.path

  • __file__表示当前文件

(1)获取当前文件路径(abspath

import os

res = os.path.abspath(__file__)
print(res)  # D:\project\python\project_study\os模块.py

(2)获取当前文件夹所在路径(dirname

import os

res = os.path.dirname(__file__)
print(res)  # D:\project\python\project_study

(3)判断当前路径是否存在(exists

import os

#先获取当前文件的路径
path = os.path.abspath(__file__)
#判断路径是否存在
res = os.path.exists(path)
#存在返回True,如果不存在则返回False
print(res)  # True

(4)拼接路径(join

import os

#获取当前文件夹路径,之后用于拼接
BASE_DIR = os.path.dirname(__file__)
print(BASE_DIR)

file_name = "doc"

#将当前文件夹路径与新的路径拼接
file_path = os.path.join(BASE_DIR, file_name)
print(file_path)
r'''
    D:\project\python\project_study\day19
    D:\project\python\project_study\day19\doc
'''

(5)切割路径(split

import os

#获取当前路径
FILE_PATH = os.path.abspath(__file__)
#对当前路径进行切割----将末尾文件切除并组成元组
file_path_list = os.path.split(FILE_PATH)
print(file_path_list)  # ('D:\\project\\python\\project_study', 'os模块.py')

(6)获取路径结尾的文件名或文件夹名(basename

import os

BASE_DIR = os.path.dirname(__file__)
FILE_PATH = os.path.abspath(__file__)
#将当前文件夹和我们输入的路径拼接起来
file_path_one = os.path.join(BASE_DIR, 'img')
#basename将我们拼接在最后的文件夹取了出来
print(os.path.basename(file_path_one))  # img
#basename将当前真正的末尾文件取出来了
# 如果path以/或\结尾,那么就会返回空值
print(os.path.basename(FILE_PATH))  # os模块.py

(7)判断当前路径是否是文件(isfile

import os

#当前文件夹路径
BASE_DIR = os.path.dirname(__file__)
#当前文件路径
FILE_PATH = os.path.abspath(__file__)
#路径是文件所以返回True
print(os.path.isfile(FILE_PATH))  # True
#路径是文件夹所以返回False
print(os.path.isfile(BASE_DIR))  # False

(8)判断当前路径是否为决定路径(isabs

import os

#os.path.abspath返回的是绝对路径
file_path_one = os.path.abspath(__file__)
#自己写一个相对路径
file_path_two = '../os模块.py'
print(os.path.isabs(file_path_one))  # True
print(os.path.isabs(file_path_two))  # False

(9)判断当前文件目录是否存在(isdir

import os

file_path_one = os.path.dirname(__file__)
file_path_two = r'../day19'
#不管是绝对路径还是相对路径都可以判断
print(os.path.isdir(file_path_one))  # True
print(os.path.isdir(file_path_two))  # True

(10)获取当前文件或目录的最后访问时间(getatime

import os
import time

file_path_one = os.path.dirname(__file__)
#之前访问过的文件夹
file_path_two = r"D:\project\python\project_study\模块.py"
time_1 = os.path.getatime(file_path_one)
time_2 = os.path.getatime(file_path_two)
#打印时间戳
print(time_1)  # 1702799155.6796083
#转化为本地时间
print(time.strftime("%Y-%m-%d  %H-%M-%S", time.localtime(time_1)))  
# 2023-12-17  15-45-55
#打印时间戳
print(time_2)  # 1702601815.0270476
#转化为本地时间
print(time.strftime("%Y-%m-%d  %H-%M-%S", time.localtime(time_2)))  
# 2023-12-15  08-56-55

(11)获取当前文件或目录的创建时间(getctime

import os
import time

file_path_one = os.path.dirname(__file__)
file_path_two = r"D:\project\python\project_study\day18\模块.py"
time_1 = os.path.getctime(file_path_one)
time_2 = os.path.getctime(file_path_two)
print(time_1)  # 1702694049.7558198
print(time.strftime("%Y-%m-%d  %H-%M-%S", time.localtime(time_1)))
# 2023-12-16  10-34-09
print(time_2)  # 1702601815.0270476
print(time.strftime("%Y-%m-%d  %H-%M-%S", time.localtime(time_2)))
# 2023-12-15  08-56-55

(12)获取当前文件或目录的修改时间(getmtime

import os
import time

file_path_one = os.path.dirname(__file__)
file_path_two = r"D:\project\python\project_study\day18\模块.py"
time_1 = os.path.getmtime(file_path_one)
time_2 = os.path.getmtime(file_path_two)
print(time_1)  # 1702799568.9183187
print(time.strftime("%Y-%m-%d  %H-%M-%S", time.localtime(time_1)))
# 2023-12-17  15-52-48
print(time_2)  # 1702601815.0270476
print(time.strftime("%Y-%m-%d  %H-%M-%S", time.localtime(time_2)))
# 2023-12-15  08-56-55

(13)返回当前文件的大小(getsize

import os

file_path_one = os.path.dirname(__file__)
file_path_two = os.path.abspath(__file__)
#因为当前文件夹不是文件,不能返回大小
print(os.path.getsize(file_path_one))  # 0
#返回文件大小,单位是字节
print(os.path.getsize(file_path_two))  # 3426

[2]路径操作(os

(1)创建单级文件夹(mkdir

import os

BASE_DIR = os.path.dirname(__file__)
#拼接出一个新的文件夹路径,并判断它是否存在
file_path = os.path.join(BASE_DIR, "img")
print(f"{file_path} 文件夹{'存在' if os.path.exists(file_path) else '不存在'}")
# D:\project\python\project_study\img 文件夹不存在
if not os.path.exists(file_path):
    #如果不存在就创建这个文件夹
    os.mkdir(file_path)

# 判断是否存在
print(f"{file_path} 文件夹{'存在' if os.path.exists(file_path) else '不存在'}")
# D:\project\python\project_study\img 文件夹存在

(2)创建多级文件夹(makedirs

import os

BASE_DIR = os.path.dirname(__file__)
#拼接出一个新的多层文件夹路径,并判断它是否存在
file_path = os.path.join(BASE_DIR, "img", "test")
print(f"{file_path} 文件夹{'存在' if os.path.exists(file_path) else '不存在'}")
# D:\project\python\project_study\img\test 文件夹不存在
if not os.path.exists(file_path):
    #如果不存在就创建这个多层文件夹
    os.makedirs(file_path)

# 判断是否存在
print(f"{file_path} 文件夹{'存在' if os.path.exists(file_path) else '不存在'}")
# D:\project\python\project_study\img\test 文件夹存在

(3)删除多级文件夹(removedirs

  • 只能删除空的文件夹
import os

BASE_DIR = os.path.dirname(__file__)
file_path = os.path.join(BASE_DIR, "img", "test")
os.makedirs(file_path)
print(f"{file_path} 文件夹{'存在' if os.path.exists(file_path) else '不存在'}")
# D:\project\python\project_study\img\test 文件夹存在
if os.path.exists(file_path):
    os.removedirs(file_path)
print(f"{file_path} 文件夹{'存在' if os.path.exists(file_path) else '不存在'}")
# D:\project\python\project_study\img\test 文件夹不存在

(4)删除单级文件夹(rmdir

import os

BASE_DIR = os.path.dirname(__file__)
file_path = os.path.join(BASE_DIR, "img")
os.makedirs(file_path)
print(f"{file_path} 文件夹{'存在' if os.path.exists(file_path) else '存在'}")
# D:\project\python\project_study\img 文件夹存在
if os.path.exists(file_path):
    os.rmdir(file_path)
print(f"{file_path} 文件夹{'存在' if os.path.exists(file_path) else '不存在'}")
# D:\project\python\project_study\img 文件夹不存在

(5)列出当前文件夹的所有文件和文件夹(lisdir

import os

print(os.listdir(os.path.dirname(__file__)))
# ['os模块.py', 'random模块.py', '__pycache__']

(6)删除指定文件(remove

import os

print(os.listdir(os.path.dirname(__file__)))
#  ['os模块.py', 'random模块.py', 'text.py', '__pycache__']
os.remove(os.path.join(os.path.dirname(__file__), "text.py"))
print(os.listdir(os.path.dirname(__file__)))
# ['os模块.py', 'random模块.py', '__pycache__']

(7)重命名文件或文件夹(rename

import os

BASE_DIR = os.path.dirname(__file__)
print(os.listdir(os.path.dirname(__file__)))
# ['os模块.py', 'random模块.py', 'test.py', '__pycache__']
file_path = os.path.join(BASE_DIR, "test.py")
os.rename(file_path, os.path.join(BASE_DIR, "test1.py"))
print(os.listdir(os.path.dirname(__file__)))
# ['os模块.py', 'random模块.py', 'test1.py', '__pycache__']

(8)获取文件夹或者文件的详细信息(stat

import os

BASE_DIR = os.path.dirname(__file__)
file_path = os.path.abspath(__file__)
base_dir_msg = os.stat(BASE_DIR)
print(base_dir_msg)
# os.stat_result(st_mode=16895, st_ino=3659174697238878, st_dev=3568160916, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1702804312, st_mtime=1702804311, st_ctime=1702694049)
file_path_mag = os.stat(file_path)
print(file_path_mag)
# os.stat_result(st_mode=33206, st_ino=4785074604081603, st_dev=3568160916, st_nlink=1, st_uid=0, st_gid=0, st_size=6476, st_atime=1702804312, st_mtime=1702804311, st_ctime=1702722306)
  • stat结构
stat 结构:

st_mode: inode 保护模式
st_ino: inode 节点号。
st_dev: inode 驻留的设备。
st_nlink: inode 的链接数。
st_uid: 所有者的用户ID。
st_gid: 所有者的组ID。
st_size: 普通文件以字节为单位的大小;包含等待某些特殊文件的数据。
st_atime: 上次访问的时间。
st_mtime: 最后一次修改的时间。
st_ctime: 由操作系统报告的"ctime"。在某些系统上(如Unix)是最新的元数据更改的时间,在其它系统上(如Windows)是创建时间(详细信息参见平台的文档)。

(9)获取当前工作目录(getcwd

import os

print(os.getcwd())
# D:\project\python\project_study

(10)改变当前工作目录(chdir

import os

print(os.getcwd())  # D:\project\python\project_study
os.chdir("D:\\project\\python")
print(os.getcwd())  # D:\project\python

(11)运行shell命令

1.直接显示
import os

res = os.system("ping www.bilibili.com")
2.获取执行结果

三、json模块

[1]序列化和反序列化

  • 将原本的字典、列表等内容转换成一个字符串的过程叫做序列化

(1)序列化有什么用

  • 我们序列化可以解决不同的程序之间数据的传输。

    • 一般我们要将一个数据传输给其他程序使用,要先将数据存到文件中在由需要数据的程序再进行读取。

    • 其中的问题是我们数据一般用到的格式都是字典、列表等类型,我们需要将数据转化为字符串类型在储存到文件之中,并且需要以特定的格式存储以方便读取。

    • 总结的说序列化就是为了:

      • 以某种存储形式使自定义对象持久化
      • 将对象从一个地方传递到另一个地方。
      • 使程序更具维护性。

    [2]反序列化方法(dumps

    • 将Python对象转换为json字符串
    import json
    
    #定义一个字典
    name_dict = {
        "name": "Xanadu",
        "age": "21",
        "sex": "male"}
    #使用.dumps方法将其转换为json字符串
    json_str = json.dumps(name_dict)
    print(json_str, type(json_str))
    # {"name": "Xanadu", "age": "21", "sex": "male"} <class 'str'>
    

[2]序列化方法

  • 将json字符串转换为Python对象
import json

#定义一个符合字典格式的json字符串
json_str = '{"name": "Xanadu", "age": "21", "sex": "male"}'
#使用.loads方法将json字符串转化为Python对象
name_dict = json.loads(json_str)
print(name_dict, type(name_dict))
# {'name': 'Xanadu', 'age': '21', 'sex': 'male'} <class 'dict'>

[3]写入文件(dump)

(1)不指定参数
import json

info_dict = {
    "name": "Xanadu",
    "age": "21",
    "sex": "male"}

#直接将Python对象转换位json字符串并写入到info.json中
with open("info.json", "w", encoding='utf-8') as f:
    json.dump(info_dict, f)

(2)指定参数编码(ensure_ascii)
import json

info_dict = {
    "name": "桃源",
    "age": "21",
    "sex": "male"
}

#当不指定ensure_ascii参数时,默认为True,会使用ascii进行解码和编码,中文会以二级制数据储存在文件中
with open("info.json", "w") as f:
    json.dump(info_dict, f)

#指定ensure_ascii参数为False的同时需要在打开文件操作时,指定编码格式为utf-8,这样json文件中就可以写入中文
with open("info.json", "w",encoding='utf-8') as f:
    json.dump(info_dict, f, ensure_ascii=False)

(3)指定参数分隔符(separators)
import json

info_dict = {
    "name": "Xanadu",
    "age": "21",
    "sex": "male"}

#将默认的分隔符,换成.
#将默认的分隔符:换成;
with open("info.json", "w") as f:
    json.dump(info_dict, f, separators=('.', ':'))

(4)其他参数
Serialize obj to a JSON formatted str.(字符串表示的json对象) 

Skipkeys:
	默认值是False
    	如果dict的keys内的数据不是python的基本类型(str,unicode,int,long,float,bool,None)设置为False时,就会报TypeError的错误。
    	此时设置成True,则会跳过这类key 

ensure_ascii:
    当它为True的时候
    	所有非ASCII码字符显示为\uXXXX序列
        只需在dump时将ensure_ascii设置为False即可
        此时存入json的中文即可正常显示。

If check_circular is false, then the circular reference check for container types will be skipped and a circular reference will result in an OverflowError (or worse). 
If allow_nan is false, then it will be a ValueError to serialize out of range float values (nan, inf, -inf) in strict compliance of the JSON specification, instead of using the JavaScript equivalents (NaN, Infinity, -Infinity). 

indent:
	应该是一个非负的整型
    	如果是0就是顶格分行显示
        如果为空就是一行最紧凑显示
        否则会换行且按照indent的数值显示前面的空白分行显示
    这样打印出来的json数据也叫pretty-printed json 

separators:
	分隔符
    	实际上是(item_separator, dict_separator)的一个元组
        默认的就是(‘,’,’:’);
        	这表示dictionary内keys之间用“,”隔开
            而KEY和value之间用“:”隔开。 

            
default(obj) is a function that should return a serializable version of obj or raise TypeError. The default simply raises TypeError. 

sort_keys:
	将数据根据keys的值进行排序。 

To use a custom JSONEncoder subclass (e.g. one that overrides the .default() method to serialize additional types), specify it with the cls kwarg; otherwise JSONEncoder is used.

[4]读取文件(load)

import json

#会从文件中读出json字符串并装换成Python对象
with open("info.json", "r", encoding='utf-8') as f:
    info_dict = json.load(f)
print(info_dict)  # {'name': 'Xanadu', 'age': '21', 'sex': 'male'}

四、hashlib模块

[1]什么是摘要算法

  • 摘要算法又称哈希算法、散列算法。
  • 摘要算法就是通过摘要函数f()对任意长度的数据data计算出固定长度的摘要digest
    • 目的是为了发现原始数据是否被人篡改过。
  • 摘要算法之所以能指出数据是否被篡改过,就是因为摘要函数是一个单向函数
    • 计算f(data)很容易,但通过digest反推data却非常困难。
    • 而且,对原始数据做一个bit的修改,都会导致计算出的摘要完全不同。

[2]摘要算法(md5)

(1)一次性加密(同一段数据)

  • 我们以常见的摘要算法MD5为例,计算出一个字符串的MD5值:
import hashlib

#第一步创建md5对象
md5 = hashlib.md5()
#将指定数据编码成二进制格式
str_mag = "Hello World"
encode_str = str_mag.encode("utf-8")
# 使用md5对象进行加密(没有返回值)
md5.update(encode_str)
# 获取加密后的值(十六进制)(常用)
print(md5.hexdigest())  # b10a8db164e0754105b7a99be72e3fe5
# 获取加密后的值(二进制)
print(md5.digest())  # b'\xb1\n\x8d\xb1d\xe0uA\x05\xb7\xa9\x9b\xe7.?\xe5'

(2)分次加密(同一段数据)

  • 如果数据量很大,可以分块多次调用update(),最后计算的结果是一样的:
import hashlib

md5 = hashlib.md5()
#直接通过b""将字符串转换成二进制的值
md5.update(b"Hello ")
md5.update(b"World")
print(md5.hexdigest())  # b10a8db164e0754105b7a99be72e3fe5
print(md5.digest())  # b'\xb1\n\x8d\xb1d\xe0uA\x05\xb7\xa9\x9b\xe7.?\xe5'

(3)使用撞库来获得加密(摘要算法)的数据

  • 因为md5等摘要算法的特点:相同的数据加密出来的加密串是相同的;不同的数据加密后一定是不同的
  • 所以可以建立一个数据与加密后的加密串一一对应的数据库,来强行破解摘要算法的加密
  • 因为数据库中一般会储存一些常见的密码数据,所以简单常见的密码较容易被撞库出来

[3]摘要算法升级之加盐

  • 摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改,但是它的单向计算特性决定了可以在不存储明文口令的情况下验证用户口令。
  • 任何允许用户登录的网站都会存储用户登录的用户名和口令。
  • 为了使验证的口令更加安全,可以使用加盐的方式进行升级
  • 加盐通过对原始口令加一个复杂字符串来实现加密算法的升级
import hashlib

str_msg = "Hello World"
str_salty = "salt"
str_msg = str_msg + str_salty

str_encode = str_msg.encode("utf-8")

md5 = hashlib.md5()
md5.update(str_encode)
#加盐后的加密串与原来的就不一样了
#且一般的“盐”会设置成一个十分复杂的字符串,撞库获得数据就会很难,即使获得了原始口令也无法分辨什么是真正的密码
print(md5.hexdigest())  # b2633dfa45ff14b507778933467d9313
print(md5.digest())  # b2633dfa45ff14b507778933467d9313

五、time模块

  • 在Python中,通常有这三种方式来表示时间:
    • 时间戳
    • 元组(struct_time)
    • 格式化的时间字符串:
      • 格式化的时间字符串(Format String): ‘1999-12-06’

[1]时间戳(time

(1)生成时间戳

  • 时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。
import time

#生成时间戳
time_str = time.time()
print(time_str)  # 1703060368.9103835

(2)时间戳转换为时间元组(UTC)

  • 将时间戳转换为UTC时间(gmtime)
import time

#生成时间戳
time_str = time.time()
print(time.gmtime(time_str))
# time.struct_time(tm_year=2023, tm_mon=12, tm_mday=20,
# tm_hour=8, tm_min=27, tm_sec=16, tm_wday=2, tm_yday=354, tm_isdst=0)

(3)时间戳转换为时间元组(本地时间)

  • 将时间戳转换为本地时间(localtime)
import time

#生成时间戳
time_str = time.time()
print(time.localtime(time_str))
# time.struct_time(tm_year=2023, tm_mon=12, tm_mday=20,
# tm_hour=16, tm_min=27, tm_sec=16, tm_wday=2, tm_yday=354, tm_isdst=0)

[2]时间字符串(strftime

import time

#生成时间字符串,字符串的格式可以定义
time_now = time.strftime("%Y-%m-%d %X") 
# %X就是将时分秒以 ”时:分:秒“ 的格式输出(本地时间)
print(time_now)  # 2023-12-20 16:32:43

'''
	%Y  Year with century as a decimal number.
    %m  Month as a decimal number [01,12].
    %d  Day of the month as a decimal number [01,31].
    %H  Hour (24-hour clock) as a decimal number [00,23].
    %M  Minute as a decimal number [00,59].
    %S  Second as a decimal number [00,61].
'''

[3]时间元组(struct_time

import time

#生成时间元组
time_tuple = time.localtime()
print(time_tuple)
# time.struct_time(tm_year=2023, tm_mon=12, tm_mday=20, 
# tm_hour=16, tm_min=39, tm_sec=49, tm_wday=2, tm_yday=354, tm_isdst=0)

#可以通过”.“ + 具体的属性名字 来读取每个值
print(time.localtime().tm_year) # 将年的属性拿出来
# 2023

#也可以通过下标打印出来
print(time.localtime()[0]) #打印的一个元素tm_year
# 2023

[4]结构化时间

(1)time.mktime(时间戳-->元组时间戳)

import time

#生成并打印时间戳
print(time.time())
#将时间戳转换为时间元组
time_tuple = time.localtime(time.time())
print(time_tuple)
#将时间元组转化为元组时间戳(去小数)
time_str = time.mktime(time_tuple)
print(time_str)

(2)time.strftime(结构化时间-->时间字符串)

  • 如果不传入结构化时间参数,就显示本地时间
import time

#格式化当前时间
time_str = time.strftime("%Y-%m-%d %X")
print(time_str)  # 2023-12-20 17:06:39

#当前时间元组
print(time.localtime(time.time()))
# time.struct_time(tm_year=2023, tm_mon=12, tm_mday=20, 
# tm_hour=17, tm_min=6, tm_sec=39, tm_wday=2, tm_yday=354, tm_isdst=0)

#格式化当前时间元组
time_local = time.strftime("%Y-%m-%d", time.localtime(time.time()))
print(time_local)  # 2023-12-20 

(3)time.strptime(时间字符串-->时间元组)

import time

#括号内的时间的间隔符要依照前面的时间
time_str = time.strptime("2023-12-20", "%Y-%m-%d")
print(time_str)
# time.struct_time(tm_year=2023, tm_mon=12, tm_mday=20,
# tm_hour=0, tm_min=0, tm_sec=0, tm_wday=2, tm_yday=354, tm_isdst=-1)

(4)time.asctime(结构化时间--> %a %b %d %H:%M:%S %Y串)

time_str = time.asctime(time.localtime(time.time()))
print(time_str)  # Wed Dec 20 17:13:44 2023

time_local = time.asctime()
print(time_local)  # Wed Dec 20 17:15:11 2023

六、datetime模块

[1]格式化输出时间

(1)格式化输出日期date(年月日)

import datetime

#格式化年月日
res = datetime.date(year=2023, month=12, day=31)
print(res)  # 2023-12-31

(2)格式化输出时间time(时分秒)

import datetime

res = datetime.time(hour=18, minute=59, second=23, microsecond=0)
print(res)  # 18:59:23

(3)格式化输出日期和时间datetime(年月日时分秒)

import datetime

res = datetime.datetime(year=2023, month=12, day=31,
                        hour=19, minute=1, second=23, microsecond=0)
print(res)  # 2023-12-31 19:01:23

[2]获取本地时间

import datetime

#获取年月日
print(datetime.date.today())  # 2023-12-20
#获取年月日时分秒
print(datetime.datetime.today())  # 2023-12-20 11:41:35.468176
#单独获取单个值
print(datetime.datetime.today().year)  # 2023
print(datetime.datetime.today().month)  # 12
#获得特定格式的日期时间
print(datetime.datetime.today().ctime())  # Wed Dec 20 22:02:47 2023

[3]打印时间的增减

  • 先定义确认时间增减的量
import datetime

#定义一个10个小时的增减量,可以用来在基础时间上进行加减
t_time = datetime.timedelta(hours=10)
print(t_time)  # 10:00:00
  • 推迟或提前时间
import datetime

t_time = datetime.timedelta(hours=10)
print(t_time)  # 10:00:00

today_time = datetime.datetime.today()
print(today_time)  # 2023-12-20 22:13:41.597755

new_time = today_time + t_time
print(new_time)  # 2023-12-21 08:14:07.816560
  • 日期对象 = 日期对象 +/- timedelta对象
  • timedelta对象 = 日期对象 +/- 日期对象

[4]案例演示

七、subprocess/sys模块

[1]subprocess.call方法(执行shell命令)

# 执行 shell 命令 没有返回值
subprocess.call(['ls'])

[2]sys.path方法(打印当前环境变量)

import sys

# sys 模块
# 【1】打印当前环境变量
path_list = sys.path
# 向系统环境变量中插入路径
path_list.insert()

# 启动文件内
path_list = sys.path
# 向系统环境变量中插入路径
path_list.insert(0, 'ATM的文件夹路径')
# 不会报错
# from ... import ...

# 网络编程 --- socket 模块
print(sys.stderr)
print(sys.stdout)

八、logging模块

[1]函数的简单配置

  • 日志的简单分级
import logging

#普通级别
logging.info("这是一条信息日志。")
#开发模式
logging.debug("这是一条调试日志。")
#警告级别
logging.warning("这是一条警告日志。")
#错误级别
logging.error("这是一条错误日志。")
# 严重错误级别
logging.critical("这是一条严重错误日志。")

[2]日志模版

import logging
import logging.config
import os
import sys

try:
    # 想要给日志上色就安装这个模块
    import coloredlogs
except Exception as e:
    if str(e) == "No module named 'coloredlogs'":
        pass

# 自定义日志级别
CONSOLE_LOG_LEVEL = "INFO"
FILE_LOG_LEVEL = "DEBUG"

# 自定义日志格式
# 打印在文件里的格式:时间戳 + 线程名 + 线程ID + 任务ID + 发出日志调用的源文件名 + 发出日志调用的源代码行号 + 日志级别 + 日志消息正文
# [2023-06-04 15:16:05][MainThread:22896][task_id:root][调用.py:12][INFO][这是注册功能]
STANDARD_FORMAT = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d][%(levelname)s][%(message)s]'
# 打印在控制台的格式:日志级别 + 时间戳 + 发出日志调用的源文件名 + 发出日志调用的源代码行号 + 日志消息正文
# [INFO][2023-06-04 15:37:28,019][调用.py:12]这是注册功能
SIMPLE_FORMAT = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
'''
参数详解:
-1.%(asctime)s: 时间戳,表示记录时间
-2.%(threadName)s: 线程名称
-3.%(thread)d: 线程ID
-4.task_id:%(name)s: 任务ID,即日志记录器的名称
-5.%(filename)s: 发出日志调用的源文件名
-6.%(lineno)d: 发出日志调用的源代码行号
-7.%(levelname)s: 日志级别,如DEBUG、INFO、WARNING、ERROR、CRITICAL等
-8.%(message)s: 日志消息正文
'''

# 日志文件路径
# os.getcwd() : 获取当前工作目录,即当前python脚本工作的目录路径
# 拼接日志文件路径 : 当前工作路径 + “logs”(日志文件路径)
LOG_PATH = os.path.join(os.getcwd(), "Activity_logs")
# OS模块 : 创建多层文件夹
# exist_ok=True 的意思是如果该目录已经存在,则不会抛出异常。
os.makedirs(LOG_PATH, exist_ok=True)
# log日志文件路径 : 路径文件夹路径 + 日志文件
LOG_FILE_PATH = os.path.join(LOG_PATH, 'Logs.log')

# 日志配置字典
LOGGING_DIC = {
    # 日志版本
    'version': 1,
    # 表示是否要禁用已经存在的日志记录器(loggers)。
    # 如果设为 False,则已经存在的日志记录器将不会被禁用,而是可以继续使用。
    # 如果设为 True,则已经存在的日志记录器将会被禁用,不能再被使用。
    'disable_existing_loggers': False,
    # 格式化程序:用于将日志记录转换为字符串以便于处理和存储。
    # 格式化程序定义了每个日志记录的输出格式,并可以包括日期、时间、日志级别和其他自定义信息。
    'formatters': {
        # 自定义格式一:年-月-日 时:分:秒
        'standard': {
            # 自定义日志格式 :时间戳 + 线程名 + 线程ID + 任务ID + 发出日志调用的源文件名 + 发出日志调用的源代码行号 + 日志级别 + 日志消息正文
            # 这里要对应全局的 STANDARD_FORMAT 配置
            'format': STANDARD_FORMAT,
            # 时间戳格式:年-月-日 时:分:秒
            'datefmt': '%Y-%m-%d %H:%M:%S'  # 时间戳格式
        },
        # 自定义格式二:
        'simple': {
            # 自定义日志格式:# 日志级别 + 时间戳 + 发出日志调用的源文件名 + 发出日志调用的源代码行号 + 日志消息正文
            # 这里要对应全局的 SIMPLE_FORMAT 配置
            'format': SIMPLE_FORMAT
        },
    },
    # 过滤器
    'filters': {},
    # 日志处理器
    'handlers': {
        # 自定义处理器名称 - 输出到控制台屏幕
        'console': {
            # 设置日志等级 为INFO
            'level': CONSOLE_LOG_LEVEL,
            # 表示该处理器将输出日志到流(stream):日志打印到控制台
            'class': 'logging.StreamHandler',
            # 日志打印格式:日志级别 + 时间戳 + 发出日志调用的源文件名 + 发出日志调用的源代码行号 + 日志消息正文
            # 这里的配置要对应 formatters 中的 simple 配置
            'formatter': 'simple'
        },
        # 自定义处理器名称 - 输出到文件
        'default': {
            # 自定义日志等级
            'level': FILE_LOG_LEVEL,
            # 标准输出到文件
            'class': 'logging.handlers.RotatingFileHandler',
            # 日志打印格式:年-月-日 时:分:秒
            # 这里的配置要对应 formatters 中的 standard 配置
            'formatter': 'standard',
            # 这里 要注意声明配置文件输出端的文件路径
            'filename': LOG_FILE_PATH,
            # 限制文件大小:1024 * 1024 * 5 = 5242880,意味着这个变量的值是 5MB(兆字节)
            # 1MB = 1024 kb
            # 1 kb = 1024 b
            'maxBytes': 1024 * 1024 * 5,
            # 表示保留最近的5个日志文件备份。
            # 当日志文件达到最大大小限制时,将会自动轮转并且保留最新的5个备份文件,以便查看先前的日志记录。
            # 当日志文件达到最大大小限制时,会自动进行轮转,后续的文件名将会以数字进行命名,
            # 例如,第一个备份文件将被重命名为原始日志文件名加上".1"的后缀,
            # 第二个备份文件将被重命名为原始日志文件名加上“.2”的后缀,
            # 以此类推,直到保留的备份数量达到设定的最大值。
            'backupCount': 5,
            # 日志存储文件格式
            'encoding': 'utf-8',
        },
    },
    # 日志记录器,用于记录应用程序的运行状态和错误信息。
    'loggers': {
        # 空字符串作为键 能够兼容所有的日志(当没有找到对应的日志记录器时默认使用此配置)
        # 默认日志配置
        '': {
            # 日志处理器 类型:打印到控制台输出 + 写入本地日志文件
            'handlers': ['default', 'console'],
            # 日志等级 : DEBUG
            'level': 'WARNING',
            # 默认情况下,当一个日志消息被发送到一个Logger对象且没有被处理时,该消息会被传递给它的父Logger对象,以便在更高层次上进行处理。
            # 这个传递过程称为“传播(propagation)”,而propagate参数指定了是否要使日志消息向上传播。
            # 将其设置为True表示应该传播消息到上一级的Logger对象;如果设置为False则不传播。
            # 表示异常将会在程序中继续传播
            # 也就是说,如果一个异常在当前的代码块中没有被处理,它将会在上级代码块或调用函数中继续向上传递,直到被某个代码块捕获或者程序退出。
            # 这是 Python 中异常处理机制的默认行为。
            # 如果将 'propagate' 设置为 False,则异常不会被传播,即使在上级代码块中没有处理异常的语句,程序也会忽略异常并继续执行。
            'propagate': True,
        },
    },
}


def set_logging_color(name='', ):
    # 初始化日志处理器 - 使用配置字典初始化日志处理器(将自定义配置加载到日志处理器中)
    # logging.basicConfig(level=logging.WARNING)
    logging.config.dictConfig(LOGGING_DIC)
    # 实例化日志处理器对象 - 并赋予日志处理器等级
    logger = logging.getLogger(name)
    # 将logger对象传递给coloredlogs.install()函数,并执行该函数以安装彩色日志记录器,使日志信息在控制台上呈现为带有颜色的格式。
    # 具体来说,该函数会使用ANSI转义序列在终端上输出日志级别、时间戳和消息等信息,并按日志级别使用不同的颜色来区分它们。这可以让日志信息更易于阅读和理解。
    coloredlogs.install(logger=logger)
    # 禁止日志消息向更高级别的父记录器(如果存在)传递。
    # 通常情况下,当一个记录器发送一条日志消息时,该消息会被传递给其所有祖先记录器,直到传递到根记录器为止。但是,通过将logger.propagate设置为False,就可以阻止该记录器的消息向上层传递。
    # 换句话说,该记录器的消息只会被发送到该记录器的处理程序(或子记录器)中,而不会传递给祖先记录器,即使祖先记录器的日志级别比该记录器要低。
    # 这种方法通常适用于需要对特定记录器进行控制,并希望完全独立于其祖先记录器的情况。
    # 确保 coloredlogs 不会将我们的日志事件传递给根 logger,这可以防止我们重复记录每个事件
    logger.propagate = False
    # 配置 日志颜色
    # 这段代码定义了一个名为coloredFormatter的变量,并将其赋值为coloredlogs.ColoredFormatter。
    # 这是一个Python库中的类,用于创建带有彩色日志级别和消息的格式化器。
    # 该变量可以用作日志记录器或处理程序的格式化程序,以使日志输出更易于阅读和理解。
    coloredFormatter = coloredlogs.ColoredFormatter(
        # fmt表示格式字符串,它包含了一些占位符,用于在记录日志时动态地填充相关信息。
        # [%(name)s]表示打印日志时将记录器的名称放在方括号内,其中name是一个变量名,将被记录器名称所替换。
        # %(asctime)s表示打印日志时将时间戳(格式化为字符串)插入到消息中,其中asctime是时间的字符串表示形式。
        # %(funcName)s表示打印日志时将函数名插入到消息中,其中funcName是函数的名称。
        # %(lineno)-3d表示打印日志时将行号插入到消息中,并且将其格式化为3位数字,其中lineno表示行号。
        # %(message)s表示打印日志时将消息本身插入到消息中。
        # 综合起来,这个格式字符串将在记录日志时输出以下信息:记录器名称、时间戳、函数名称、行号和日志消息。
        # 记录器名称 + 时间戳 + 函数名称 + 行号 + 日志消息
        # [root] 2023-06-04 16:00:57 register 15   this is an info message
        fmt='[%(name)s] %(asctime)s %(funcName)s %(lineno)-3d  %(message)s',
        # 级别颜色字典
        level_styles=dict(
            # debug 颜色:白色
            debug=dict(color='white'),
            # info 颜色:蓝色
            info=dict(color='blue'),
            # warning 颜色:黄色 且 高亮
            warning=dict(color='yellow', bright=True),
            # error 颜色:红色 且 高亮 且 加粗
            error=dict(color='red', bold=True, bright=True),
            # critical 颜色:灰色 且 高亮 且 背景色为红色
            critical=dict(color='black', bold=True, background='red'),
        ),
        # 这段代码定义了一个名为field_styles的字典 , 其中包含四个键值对。
        # 每个键代表日志记录中的不同字段,而每个值是一个字典,它指定了与该字段相关联的样式选项。
        # 具体来说,这些字段和样式选项如下:
        # name:指定记录器的名称,将使用白色颜色。
        # asctime:指定日志记录的时间戳,将使用白色颜色。
        # funcName:指定记录消息的函数名称,将使用白色颜色。
        # lineno:指定记录消息的源代码行号,将使用白色颜色。
        field_styles=dict(
            name=dict(color='white'),
            asctime=dict(color='white'),
            funcName=dict(color='white'),
            lineno=dict(color='white'),
        )
    )

    ## 配置 StreamHandler:终端打印界面
    # 这行代码定义了一个名为ch的日志处理器。
    # 具体来说,它是logging.StreamHandler类的一个实例,用于将日志输出到标准输出流(即控制台)中。
    # 在创建StreamHandler对象时,需要指定要使用的输出流
    # 因此stream=sys.stdout参数指定了该对象将把日志写入到标准输出流中.
    ch = logging.StreamHandler(stream=sys.stdout)
    # 这段代码是 Python 中用于设置日志输出格式的语句。
    # 它使用了一个名为 coloredFormatter 的格式化器对象,并将其传递给 ch.setFormatter() 方法来指定输出日志的样式。
    # 具体来说,ch 是一个 Logger 对象,它代表了整个日志系统中的一个记录器。
    # 可以通过该对象来控制日志的级别、输出位置等行为。而 setFormatter() 方法则用于设置该 Logger 输出日志的格式化方式
    # 这里传递的是 coloredFormatter 格式化器对象。
    # 在实际应用中,coloredFormatter 可以是自定义的 Formatter 类或者已经存在的 Formatter 对象。
    # 这里 将 coloredFormatter - 彩色输出日志信息的格式化器 传入进去。
    ch.setFormatter(fmt=coloredFormatter)
    # 这段代码是在Python中添加一个日志记录器(logger)的处理器(handler)。其中,hdlr参数是指定要添加到记录器(logger)中的处理器(handler)对象,ch是一个代表控制台输出的处理器对象。
    # 这行代码的作用是将控制台输出的信息添加到日志记录器中。
    logger.addHandler(hdlr=ch)
    # 这段代码用于设置日志级别为DEBUG,也就是最低级别的日志记录。
    # 意思是在程序运行时,只有DEBUG级别及以上的日志信息才会被记录并输出,而比DEBUG级别更低的日志信息则不会被记录或输出。
    # DEBUG(调试)、INFO(信息)、WARNING(警告)、ERROR(错误)和CRITICAL(严重错误)。
    logger.setLevel(level=logging.DEBUG)
    # 返回日志生成对象
    return logger


def get_logger(name='', ):
    '''
    :param name: 日志等级
    :return:
    '''
    # 初始化日志处理器 - 使用配置字典初始化日志处理器(将自定义配置加载到日志处理器中)
    logging.config.dictConfig(LOGGING_DIC)
    # 实例化日志处理器对象 - 并赋予日志处理器等级
    logger = logging.getLogger(name)
    # 返回日志生成对象
    return logger


if __name__ == "__main__":
    # # 示例:
    # # (1)初始化日志处理器 - 使用配置字典初始化日志处理器(将自定义配置加载到日志处理器中)
    # logging.config.dictConfig(LOGGING_DIC)
    # # (2)实例化日志处理器对象 - 并赋予日志处理器等级
    # # # logger1 = logging.getLogger('') # 默认为 '' 即以默认配置进行实例化
    # logger1 = logging.getLogger('')
    # # (3)当日志发生时,打印的提示语
    # logger1.debug('这是日志生成语句')
    logger_nor = get_logger()
    # 输出到屏幕上
    logger_nor.warning(msg="this is a warning message")
    logger_col = set_logging_color()
    # debug : 输出到文件里
    logger_col.critical(msg="this is a critical message")

九、re模块(正则模块)

[1]正则语法基础

(1)字符组

  • 字符组 :[字符组] 在同一个位置可能出现的各种字符组成了一个字符组
  • 在正则表达式中用[]表示
  • 字符分为很多类
    • 比如数字、字母、标点等等。
字符组 待匹配字符 匹配结果 说明
[0123456789] 6 Ture 待匹配字符如果在字符组里面,就可以匹配
[0123456789] a False 待匹配字符如果不在字符组里面,就无法匹配
[0-9] 7 Ture 使用-连结左右两边的范围,也可以放入字符组表示本身以及之间的字符
[a-z] a Ture 字符也可以使用-,按照字母表的顺序,取得符号
[A-Z] A Ture 大写字母也相同
[0-9a-zA-Z] a Ture 可以将不用的范围直接放入同一个字符组
  • re.findall(正则模式,文本) 基于基于正则模式查找所有匹配的文本内容
ret1 = re.findall("a", "a,b,c,d,e")  # a
ret1 = re.findall(".", "a,b,c,d,e")  
# ['a', ',', 'b', ',', 'c', ',', 'd', ',', 'e']
ret1 = re.findall("[ace]", "a,b,c,d,e")
# ['a', 'c', 'e']
ret1 = re.findall("[a-z]", "a,b,c,d,e")
# ['a', 'b', 'c', 'd', 'e']
ret1 = re.findall("[0-9]", "1,2,3,4,5")
# ['1', '2', '3', '4', '5']
ret1 = re.findall("\d", "1,2,3,4,5")
# ['1', '2', '3', '4', '5']
ret1 = re.findall("[0-9a-z]", "1,a,2,b,3")
# ['1', 'a', '2', 'b', '3']
ret1 = re.findall("[^a-z]", "1,a,2,b,3")
# ['1', ',', ',', '2', ',', ',', '3']
ret1 = re.findall("[^0-9,]", "1,a,2,b,3")
#['a', 'b']

(2)元字符

  • 以特殊字符组合而成,代表特殊含义的组合
元字符 匹配内容
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线
\s 匹配任意的空白符
\d 匹配数字
\n 匹配一个换行符
\t 匹配一个制表符
\b 匹配一个单词的结尾
^ 匹配字符串的开始
$ 匹配字符串的结尾
\W 匹配非字母或数字或下划线
\D 匹配非数字
\S 匹配非空白符
a|b 匹配字符a或字符b
() 匹配括号内的表达式,也表示一个组
[...] 匹配字符组中的字符
[^...] 匹配除了字符组中字符的所有字符
ret2 = re.findall("[0-9a-zA-Z]", "apple,banana,orange,melon")
# 其结果会将所有数字和大小写字母一个个输出来
ret2 = re.findall("\w", "apple,banana,orange,melon")
# 其结果会将所有数字和大小写字母还有下划线一个个输出来

(3)量词

  • 其实就是控制正则表达式中匹配到的字符的次数
量词 用法说明
* 重复零次或更多次
+ 重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次
ret3 = re.findall("\w+", "apple,banana,orange,melon")
# ['apple', 'banana', 'orange', 'melon'] 
# 一直匹配字母数字或者下划线,直到遇到其他字符跳过,然后继续匹配
ret3 = re.findall("\w+?", "apple,banana,orange,melon")  # 取消贪婪匹配
# 只添加+号会使\wy一直匹配下去直到遇到其他字符,之后有加上?,前面所有匹配到的字符就只能重复最多一次就会输出
# 结果就是一个个字母输出
ret3 = re.findall("\w*", "apple,banana,orange,melon")
# ['apple', '', 'banana', '', 'orange', '', 'melon', '']
# 一直匹配字母数字或者下划线,直到遇到其他字符输出空,然后继续匹配
ret3 = re.findall("\w{6}", "apple,banana,orange,melon")
# ['banana', 'orange'] 只有重复6次的数字、字符或者下划线的组合才能输出

(4)位置元字符. ^ $

正则 待匹配字符 匹配 结果 说明
海. 懦夫懦弱懦米 懦夫懦弱懦米 匹配所有"懦."的字符
^海. 懦夫懦弱懦米 懦夫 只从开头匹配"懦."
海.$ 懦夫懦弱懦米 懦米 只匹配结尾的"懦.$"

(5)重复匹配\ * + ? {}

正则 待匹配字符 匹配 结果 说明
李.? 李华和李云龙和李波棱盖 李华 李云 李波 ?表示重复零次或一次,即只匹配"李"后面一个任意字符
李.* 李华和李云龙和李波棱盖 李华和李云龙和李波棱盖 *表示重复零次或多次,即匹配"李"后面0或多个任意字符
李.+ 李华和李云龙和李波棱盖 李华和李云龙和李波棱盖 +表示重复一次或多次,即只匹配"李"后面1个或多个任意字符
李.{1,2} 李华和李云龙和李波棱盖 李华和 李云龙 李波棱 {1,2}匹配1到2次任意字符

(6)字符集[][^]

正则 待匹配字符 匹配 结果 说明
李[华云龙波棱盖]* 李华和李云龙和李波棱盖 李华 李云龙 李波棱盖 表示匹配"李"字后面[杰莲英二棍子]的字符任意次
李[^和]* 李华和李云龙和李波棱盖 李华 李云龙 李波棱盖 表示匹配一个不是"和"的字符任意次
[\d] 456bdha3 4 5 6 3 表示匹配任意一个数字,匹配到4个结果
[\d]+ 456bdha3 456 3 表示匹配任意个数字,匹配到2个结果

(7)分组匹配 ()与 或 |[^]

  • 身份证号码是一个长度为15或18个字符的字符串
    • 如果是15位则全部由数字组成,首位不能为0;
    • 如果是18位,则前17位全部是数字,末位可能是数字或x,
    • 下面我们尝试用正则来表示:
正则 待匹配字符 匹配 结果 说明
^[1-9]\d{13,16}[0-9x]$ 110101198001017032 110101198001017032 表示可以匹配一个正确的身份证号
^[1-9]\d{13,16}[0-9x]$ 1101011980010170 1101011980010170 表示也可以匹配这串数字,但这并不是一个正确的身份证号码,它是一个16位的数字
^[1-9]\d{14}(\d{2}[0-9x])?$ 1101011980010170 False 现在不会匹配错误的身份证号了 ()表示分组,将\d{2}[0-9x]分成一组,就可以整体约束他们出现的次数为0-1次
`^([1-9]\d{16}[0-9x] [1-9]\d{14})$` 110105199812067023 110105199812067023

(8)转义符\

  • 在正则表达式中,有很多有特殊意义的是元字符
    • 比如\n和\s等
    • 如果要在正则中匹配正常的"\n"而不是"换行符"就需要对""进行转义,变成''。
  • 在python中,无论是正则表达式,还是待匹配的内容,都是以字符串的形式出现的,在字符串中\也有特殊的含义,本身还需要转义。
  • 所以如果匹配一次"\n",字符串中要写成'\n',那么正则里就要写成"\n",这样就太麻烦了。
  • 这个时候我们就用到了r'\n'这个概念,此时的正则是r'\n'就可以了。
正则 待匹配字符 匹配 结果 说明
\n \n False 因为在正则表达式中\是有特殊意义的字符,所以要匹配\n本身,用表达式\n无法匹配
\n \n True 转义\之后变成\,即可匹配
"\n" '\n' True 如果在python中,字符串中的''也需要转义,所以每一个字符串''又需要转义一次
r'\n' r'\n' True 在字符串之前加r,让整个字符串不转义

(10)贪婪匹配

  • 贪婪匹配:在满足匹配时,匹配尽可能长的字符串,默认情况下,采用贪婪匹配
正则 待匹配字符 匹配 结果 说明
<.*> <script>...<script> <script>...<script> 默认为贪婪匹配模式,会匹配尽量长的字符串
<.*?> r'\d' <script> <script> 加上?为将贪婪匹配模式转为非贪婪匹配模式,会匹配尽量短的字符串
  • 几个常用的非贪婪匹配,Pattern
  • *? 重复任意次,但尽可能少重复
  • +? 重复1次或更多次,但尽可能少重复
  • ?? 重复0次或1次,但尽可能少重复
  • {n,m}? 重复n到m次,但尽可能少重复
  • {n,}? 重复n次以上,但尽可能少重复

(10)模式修正符

  • . 是任意字符

  • * 是取 0 至 无限长度

  • ? 是非贪婪模式。

  • 合在一起就是取尽量少的任意字符,一般不会这么单独写

    • 他大多用在:.*? 就是取前面任意长度的字符,直到一个x出现
  • 模式修正符,也叫正则修饰符,模式修正符就是给正则模式增强或增加功能的。

说明
re.I 是匹配对大小写不敏感
re.L 做本地化识别匹配
re.M 多行匹配,影响到^和$
re.S 使.匹配包括换行符在内的所有字符
re.U 根据Unicode字符集解析字符,影响\w、\W、\b、\B
re.X 通过给予我们功能灵活的格式以便更好的理解正则表达式

[2]正则模块的常用方法

(1)编译正则表达式(compile

re_type = re.compile(pattern=r'\w')
print(re_type)  # re.compile('\\w')

(2)查找结构(findall

my_str = 'my name is Xanadu.'
查找结果
res = re.findall(pattern=r'\w', string=my_str)
print(res)
['m', 'y', 'n', 'a', 'm', 'e', 'i', 's', 'X', 'a', 'n', 'a', 'd', 'u']

(3)查找结果(search

res_2 = re.search(re_type, my_str)
# print(res_2)  # <re.Match object; span=(0, 1), match='m'>
re_type = re.compile(r"[\w].")
res_3 = re.search(re_type, my_str).group()
print(res_3)  # my
res_4 = re.search(re_type, my_str).groups()
print(res_4)

(4)查找结果(match

res_6 = re.match(re_type, my_str)
print(res_6)  # <re.Match object; span=(0, 2), match='my'>
res_7 = re.match(re_type, my_str).group()
print(res_7)  # my

(5)切割(split

my_str = "123456789"
re_type = re.compile(r"2")
res_8 = re.split(re_type, my_str)
print(res_8)  # ['1', '3456789']

(6)指定个数替换(sub

re.subn(pattern=正则表达式,repl=替换进去的内容,string=待匹配的内容,count=修改字符的个数)
my_str = "my name is Xanadu"
re_type = re.compile("X")
res_9 = re.sub(re_type, "x", my_str, 1)
print(res_9)  # my name is xanadu

(7)替换全部(subn

re.sub(pattern=正则表达式,repl=替换进去的内容,string=待匹配的内容,count=修改字符的个数)
res_10 = re.subn(re_type, "x", my_str, 1)
print(res_10)  # ('my name is xanadu', 1)

(8)匹配结果为迭代器(finditer

my_str = "1212akad12"
re_type = re.compile(r"\d*")
res_11 = re.finditer(re_type, my_str)
print(res_11)  # <callable_iterator object at 0x000002B45604A620>
for i in res_11:
    print(i)

'''
    <re.Match object; span=(0, 4), match='1212'>
    <re.Match object; span=(4, 4), match=''>
    <re.Match object; span=(5, 5), match=''>
    <re.Match object; span=(6, 6), match=''>
    <re.Match object; span=(7, 7), match=''>
    <re.Match object; span=(8, 10), match='12'>
    <re.Match object; span=(10, 10), match=''>
'''

[3]正则方法之优先级

(1)findall的优先级查询

import re

ret = re.findall('www.(baidu|oldboy).com', 'www.oldboy.com')
# 这是因为findall会优先把匹配结果组里内容返回,如果想要匹配结果,取消权限即可
print(ret)  # ['oldboy']     

ret = re.findall('www.(?:baidu|oldboy).com', 'www.oldboy.com')
print(ret)  # ['www.oldboy.com']

(2)split的优先级查询

ret=re.split("\d+","eva3egon4yuan")
print(ret) #结果 : ['eva', 'egon', 'yuan']

ret=re.split("(\d+)","eva3egon4yuan")
print(ret) #结果 : ['eva', '3', 'egon', '4', 'yuan']
  • 在匹配部分加上()之后所切出的结果是不同的,
  • 没有()的没有保留所匹配的项,但是有()的却能够保留了匹配的项,
  • 这个在某些需要保留匹配部分的使用过程是非常重要的。

[4]常用正则表达式

场景 正则表达式
用户名 ^[a-z0-9_-]{3,16}$
密码 ^[a-z0-9_-]{6,18}$
手机号码 ^(?:\+86)?1[3-9]\d{9}$
颜色的十六进制值 ^#?([a-f0-9]
电子邮箱 ^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+\.[a-z]+$
URL ^(?:https://
IP 地址 ((2[0-4]\d
HTML 标签 ^<([a-z]+)([^<]+)*(?:>(.*)<\/\1>
utf-8编码下的汉字范围 ^[\u2E80-\u9FFF]+$