欢迎来到JIA的博客

我的python学习之路-递归/内置函数/模块/正则

本节内容:

  一、递归函数

    1.1 基本写法

    1.2  练习题

      1.2.1  使用递归完成任意数n的阶乘

      1.2.2  使用尾递归完成任意数n的阶乘

      1.2.3  使用递归完成斐波那契数列

  二、内置函数

    2.1 abs 绝对值函数

    2.2 round 四舍五入

    2.3 sum 计算一个序列的和

    2.4  max  min 获取一个序列里边的最大值 最小值

    2.5  pow    计算某个数值的x次方

    2.6  进制转化函数

    2.7  字符和ASCII转化函数

    2.8  字符串转换成Python代码函数

    2.9  repr   不转义字符输出字符串 [等价于元字符串]

    2.10  hash   生成哈希值

  三、模块

    3.1  数学模块 math

    3.2  随机模块 random

    3.3 pickle 序列化模块

       3.4 json 模块

       3.5 time 时间模块

    3.6 压缩模块zipfile (后缀为zip)

     3.7  OS模块  对系统进行操作

     3.8 shutil模块 复制/移动/

     3.9 tarfile 模块 后缀为.tar  |  .tar.gz  |   .tar.bz2

 四、正则表达式 

     4.1 匹配单个字符

     4.2 多个字符匹配

     4.3 匹配分组 ()表达一个整体

     4.4 反向引用

     4.5 命名分组

     4.6 正则函数

    4.7修饰符

 

一、 递归函数

定义:自己调用自己的函数,就是递归函数

  递:去     归:回      一去一回是递归

1、基本写法

def digui(n):
    print(n,"<----start---->")
    if n>0:
        digui(n-1)
    print(n,"<-----end----->")
    
digui(5)

代码解析:

去的过程:

n = 5 print(5,"<--start-->") if 5 > 0 digui(n - 1) => digui(4) 代码阻塞在第13行

n = 4 print(4,"<--start-->") if 4 > 0 digui(n - 1) => digui(3) 代码阻塞在第13行

n = 3 print(3,"<--start-->") if 3 > 0 digui(n - 1) => digui(2) 代码阻塞在第13行
n = 2 print(2,"<--start-->") if 2 > 0 digui(n - 1) => digui(11 代码阻塞在第13行
n = 1 print(1,"<--start-->") if 1 > 0 digui(n - 1) => digui(0) 代码阻塞在第13行
n = 0 print(0,"<--start-->") if 0 > 0 条件不满足 print(0,"<--end-->")

[如果最后一层函数执行结束,将触发归的过程,把没执行完的代码执行结束.]

归的过程:
n = 1 走到上一次代码阻塞13行的位置,往下走 print(1,"<--end-->")
n = 2 走到上一次代码阻塞13行的位置,往下走 print(2,"<--end-->")
n = 3 走到上一次代码阻塞13行的位置,往下走 print(3,"<--end-->")
n = 4 走到上一次代码阻塞13行的位置,往下走 print(4,"<--end-->")
n = 5 走到上一次代码阻塞13行的位置,往下走 print(5,"<--end-->")

栈帧空间:函数调用时,每次调用都会在内存中独立开辟一个空间,叫做栈帧空间,
是独立的副本,空间和空间之间数据不共享

总结:
(1)递归就是不停的开辟和不停的释放栈帧空间的过程,整合在一起时递归
(2)触发递归函数归的过程有两种:
(1) 递归在最后一层栈帧空间代码全部执行结束的时候,触发归的过程
(2) 遇到函数中的return,回到上一层栈帧空间从阻塞处继续向下执行
(3) 在写递归时,务必给与递归跳出的条件,不能无限递归下去,否则内存溢出,蓝屏死机
(4) 如果递归的层次太深,不建议使用递归;(官方说法1000层,因个人电脑而已

 2、练习题

1.使用递归完成任意数n的阶乘

def jiecheng(n):
    if 0<= n <=1:
        return 1
    return n * jiecheng(n-1)

代码解析

 1 '''
 2 去的过程:
 3 n = 5  return n * jiecheng(n-1)    => return 5 * jiecheng(4)
 4 n = 4  return n * jiecheng(n-1) => return 4 * jiecheng(3)
 5 n = 3  return n * jiecheng(n-1) => return 3 * jiecheng(2)
 6 n = 2  return n * jiecheng(n-1) => return 2 * jiecheng(1)
 7 n = 1  return 1
 8 
 9 归的过程:
10 n = 2  return n * jiecheng(n-1) => return 2 * 1
11 n = 3  return n * jiecheng(n-1) => return 3 * 2 * 1
12 n = 4  return n * jiecheng(n-1) => return 4 * 3 * 2 * 1
13 n = 5  return n * jiecheng(n-1) => return 5 * 4 * 3 * 2 * 1
14 所有代码执行结束 : 返回 return 5 * 4 * 3 * 2 * 1 => 120
15 '''
View Code

 

2.使用尾递归完成任意数n的阶乘

尾递归: 自己调用自己,且非表达式
特点 : 计算的结果在参数中运算;

def jiecheng(n,endval):
    if n <= 1:
        return endval
    return jiecheng(n-1,n*endval)
print(jiecheng(5,1))

尾递归的特点:最后一层函数调用结束后的返回值,就是最顶级函数调用的结果,
所以我们的思维逻辑只考虑递去的过程即可,归的思维逻辑可以不考虑了;
需要在写递归时,在参数运算时动脑筋;

代码解析:

 1 """
 2 代码去的过程:
 3 n = 5 , endval = 1 if n <= 1: 条件不成立 return jiecheng(5-1,5*1) => jiecheng(4,5*1)
 4 n = 4 , endval = 5*1 if n <= 1: 条件不成立 return jiecheng(4-1,4*5*1) => jiecheng(3,4*5*1)
 5 n = 3 , endval = 4*5*1 if n <= 1: 条件不成立 return jiecheng(3-1,3*4*5*1) => jiecheng(2,3*4*5*1)
 6 n = 2 , endval = 3*4*5*1 if n <= 1: 条件不成立 return jiecheng(2-1,2*3*4*5*1) => jiecheng(1,2*3*4*5*1)
 7 n = 1 , endval = 2*3*4*5*1 if n <= 1: 条件成立 return endval [2*3*4*5*1]
 8 
 9 递归归的过程:
10 最后一层结果就是函数顶级调用的结果.一深直入;
11 
12 """
View Code

尾递归在一些特别的解释器中,每次调用函数时,都只在内存中开辟一个栈帧空间,

后者替换前者,只要最后一层空间有数据返回,直接结束.
但是目前cpython解释器不支持,仍然是有去有回;

优化代码

# 优化代码1
def jiecheng(n,endval=1):
    if n <= 1:
        return endval
    return jiecheng(n-1,n*endval)
print(jiecheng(5,1))

# 优化代码2
def outer(n):
    def jiecheng(n,endval=1):
        if n <= 1:
            return endval
        return jiecheng(n-1,n*endval)
    return jiecheng(5,1)

print(outer(5))

3.使用递归完成斐波那契数列

def feb(n):
    if n == 1 or n == 2:
        return 1
    #      寻找上一个值 + 寻找上上个值
    return feb(n - 1) + feb(n - 2)
print(feb(5))

 

 

 二、内置函数

1、abs    绝对值函数

res = abs(-1)
print(res)

2、round 四舍五入

(n.5 n为偶数则舍去 n.5 n为奇数,则进一!)

res = round(3.69)#4
res = round(3.5)#4
res = round(4.5) #4
res = round(4.51)#5

3、sum    计算一个序列的和

lst =[1,2,3,4]
res = sum(lst)

4、max  min 获取一个序列里边的最大值 最小值

lst = [100,200,20,-3]
# max 获取一个序列里边的最大值
res = max(lst)
# min 获取一个序列里边的最小值
res = min(lst)
print(res

其他方法

lst = sorted(lst)
maxval = lst[-1]
minval = lst[0]
print(maxval,minval)

max与min的高阶用法与sorted相同
return 最终返回的数据和传入到自定义函数中的数据是一致的

container = {"何子豪":100,"李雅琪":200,"王雨涵":300}
def func(n):
    print(container[n])
    # 返回的是年龄,按照年龄找到最大值最小值
    return container[n]

res = max(container,key=func)
res = min(container,key=func)
print(res)

5、pow    计算某个数值的x次方

# pow    计算某个数值的x次方
res = pow(2,3)
# 前2个参数的结果和第三个参数取余
res = pow(2,3,5)
print(res)

6、进制转化函数

# bin    将10进制数据转化为二进制
res = bin(255)
print(res)

# oct    将10进制数据转化为八进制
res = oct(8)
print(res)

# hex    将10进制数据转化为16进制
res = hex(255)
print(res)

7、字符和ASCII转化函数

# chr    将ASCII编码转换为字符
res = chr(97)
print(res)
# ord    将字符转换为ASCII编码
res = ord("a")
print(res)

8、字符串转换成Python代码函数

# eval   将字符串当作python代码执行 (慎用)
strvar = "print(123434343434)"
strvar = "a=100"
# print(strvar)
# eval(strvar) error

# exec   将字符串当作python代码执行(功能更强大) (慎用)
strvar = "a=100"
strvar = """
for i in range(50):
    print(i)
"""
exec(strvar)

9、repr   不转义字符输出字符串 [等价于元字符串]

pathvar = "D:\notepadd++\t"
print(repr(pathvar))

10、hash   生成哈希值

res1 = hash("a")
res2 = hash("a")
print(res1,res2)

 

 三、模块

 1、数学模块 math

 1 import math
 2 #ceil()  向上取整操作 (对比内置round) ***
 3 res = math.ceil(3.1)
 4 res = math.ceil(-3.5)
 5 print(res)
 6 
 7 #floor() 向下取整操作 (对比内置round) ***
 8 res = math.floor(4.199)
 9 res = math.floor(-4.199)
10 print(res)
11 
12 #pow()  计算一个数值的N次方(结果为浮点数) (对比内置pow) ***
13 res = math.pow(2,3)
14 # math中的pow方法没有三个参数,只有2个;
15 # res = math.pow(2,3,2) error
16 print(res)
17 
18 #sqrt() 开平方运算(结果浮点数) ***
19 res = math.sqrt(9)
20 print(res) # 3.0
21 
22 #fabs() 计算一个数值的绝对值 (结果浮点数) (对比内置abs)
23 res = math.fabs(-999)
24 print(res)
25 
26 #modf() 将一个数值拆分为整数和小数两部分组成元组
27 res = math.modf(3.567)
28 print(res)
29 
30 #copysign()  将参数第二个数值的正负号拷贝给第一个 (返回一个小数)
31 res = math.copysign(-18,-19)
32 print(res)
33 
34 #fsum() 将一个容器数据中的数据进行求和运算 (结果浮点数)(对比内置sum)
35 lst = [1,2,3,4]
36 print(math.fsum(lst))
37 
38 #圆周率常数 pi ***
39 res = math.pi
40 print(res)
View Code

2、随机模块 random

 1、random() 获取随机0-1之间的小数(左闭右开)

import re
res = random.random()
print(res)

2、randrange() 随机获取指定范围内的整数(包含开始值,不包含结束值,间隔值)

# 一个参数
res = random.randrange(5)
print(res)

# 二个参数
res = random.randrange(1,7)
print(res)

# 三个参数
res = random.randrange(1,10,3) # 1 4 7 
print(res)

3、randint()   随机产生指定范围内的随机整数 (了解)

res = random.randint(1,4) # 留头留尾
print(res)

4、uniform() 获取指定范围内的随机小数(左闭右开) 

res = random.uniform(2,4) # 2 <= x < 4
res = random.uniform(4,2) # 2 < x <= 4
print(res)

5、choice()  随机获取序列中的值(多选一)

lst = ["耿择时","孙翔宇","家营和","张银"]
res = random.choice(lst)
print(res

6、sample()  随机获取序列中的值(多选多) [返回列表]

lst = ["耿择时","孙翔宇","家营和","张银"]
res = random.sample(lst,2)
print(res) # 返回列表

7、shuffle() 随机打乱序列中的值(直接打乱原序列)

lst = [1,2,3,4,45,5,6]
random.shuffle(lst)
print(lst) #[3, 5, 4, 6, 45, 2, 1]

8、验证码功能

 1 def yanzhengma():
 2     strvar = ""
 3     for i in range(4):
 4         # 元素中包含数字
 5         num = str(random.randrange(10))
 6         # 元素中含有小写字母
 7         s_c = chr(random.randrange(97,123))
 8         # 元素中含有大写字母
 9         b_c = chr(random.randrange(65,91))
10         # 把可能的元素扔到列表中,随机抽
11         lst = [num,s_c,b_c]
12         # 把随机抽取的4次内容都叠加到字符串strvar中
13         strvar += random.choice(lst)
14     return strvar
View Code

3、 pickle 序列化模块

序列化:   把不能够直接存储的在文件中的数据变得可存储

反序列化 :把存储的数据拿出来恢复成原来的数据类型

 需要配合文件操作 使用 dump 和 load

不需要配合文件操作 使用 dumps 和 loads

1、dump  把对象序列化后写入到file-like Object(即文件对象)

lst = [1,12,3,4]
with open("ceshi1.txt",mode="wb") as fp:
    pickle.dump(lst,fp)

2、load  把file-like Object(即文件对象)中的内容拿出来,反序列化成原来数据

with open("ceshi1.txt",mode="rb") as fp:
    res = pickle.load(fp)
print(res,type(res))

3、dumps 把任意对象序列化成一个bytes

# 序列化函数
def func():
    print("我是func函数 ... ")

res = pickle.dumps(func)
print(res)

4、loads 把任意bytes反序列化成原来数据

# 反序列化函数字节流
func = pickle.loads(res)
func()

5、使用dumps 和 loads 将数据存储到文件中

with open("ceshi1.txt",mode="wb") as fp:
    res1 = pickle.dumps(it)
    fp.write(res1)

with open("ceshi1.txt",mode="rb") as fp:
    res = fp.read()
    it = pickle.loads(res)
print(next(it))
print(next(it))

4、json 模块

所有编程语言都能够识别的数据格式叫做json,是字符串
能够转换的数据格式 : int float bool str list tuple dict None

json : 一般用来做数据的传输,序列化成字符串
pickle : 一般用来做数据的存储,序列化成字节流

1.json 的用法

(1)json中的 dumps 和  loads 
dic = {"name":"于盛林","age":25,"sex":"男性","family":["老于","小鱼","小小鱼"]}

# 序列化
# ensure_ascii=False 显示中文 , sort_keys=False 对字典的键进行排序
res = json.dumps(dic,ensure_ascii=False,sort_keys=True) 
print(res , type(res))

# 反序列化
dic = json.loads(res)
print(dic, type(dic))
(2)json中的  dump 和 load
with open("ceshi2.txt",mode="w",encoding="utf-8") as fp:
    json.dump(dic,fp,ensure_ascii=False)

with open("ceshi2.txt",mode="r",encoding="utf-8") as fp:
    dic = json.load(fp)
print(dic,type(dic))

2.json 和 pickle 之间的区别

(1)json

json可以连续dump , 但是不能连续的load
load是一次性把所有数据拿出来反序列化成原来的数据类型

 1 """ 
 2 dic1 = {"a":1,"b":2}
 3 dic2 = {"c":3,"d":4}
 4 # 连续dump
 5 with open("ceshi3.txt",mode="w",encoding="utf-8") as fp:
 6     json.dump(dic1,fp)
 7     fp.write("\n")
 8     json.dump(dic2,fp)
 9     fp.write("\n")
10 
11 # 连续load error 
12 """
13 with open("ceshi3.txt",mode="r",encoding="utf-8") as fp:
14     json.load(fp)
15     json.load(fp)
16 """
17 # 解决
18 with open("ceshi3.txt",mode="r",encoding="utf-8") as fp:
19     for i in fp:
20         dic = json.loads(i)
21         print(dic, type(dic))
View Code
(2)pickle

pickle可以连续dump , 也能连续的load

 1 import pickle
 2 dic1 = {"a":1,"b":2}
 3 dic2 = {"c":3,"d":4}
 4 # 连续dump
 5 with open("ceshi4.txt",mode="wb") as fp:
 6     pickle.dump(dic1,fp)
 7     pickle.dump(dic2,fp)
 8     
 9 # 连续load
10 with open("ceshi4.txt",mode="rb") as fp:
11     dic1 = pickle.load(fp)
12     print(dic1 , type(dic1))
13     dic2 = pickle.load(fp)
14     print(dic2 , type(dic2))
View Code

一次性把所有数据全部拿取出来

with open("ceshi4.txt",mode="rb") as fp:
    try:
        while True:            
            dic = pickle.load(fp)
            print(dic , type(dic))
    except:
        pass
(3)json 和 pickle 两个模块的区别

(1)json序列化之后的数据类型是str,所有编程语言都识别,

   但是仅限于(int float bool)(str list tuple dict None)

   json不能连续load,只能一次性拿出所有数据

(2)pickle序列化之后的数据类型是bytes,

   所有数据类型都可转化,但仅限于python之间的存储传输.

   pickle可以连续load,多套数据放到同一个文件中

5、time 时间模块

 1 import time
 2 #time()          获取本地时间戳
 3 res = time.time()
 4 print(res)
 5 
 6 # localtime  =>  mktime  =>  ctime
 7 # 返回元组   =>  返回时间戳 =>  时间字符串
 8 # 1.localtime()     获取本地时间元组         (参数是时间戳,默认当前)
 9 res = time.localtime()
10 print(res)
11 # 指定时间戳
12 ttp = time.localtime(1600000000)
13 print(ttp)
14 
15 # 2.mktime()        通过时间元组获取时间戳    (参数是时间元组)
16 ttp = (2020,12,9,11,5,59,0,0,0)
17 res = time.mktime(ttp)
18 print(res)
19 
20 # 3.ctime()         获取本地时间字符串(参数是时间戳,默认当前)
21 res = time.ctime()
22 print(res)
23 
24 # 指定时间戳
25 res = time.ctime(1607483245)
26 print(res)
27 
28 
29 #asctime()       通过时间元组获取时间字符串(参数是时间元组) (了解)
30 """不能自动识别周几"""
31 ttp = (2020,12,9,11,5,59,0,0,0)
32 res = time.asctime(ttp)
33 print(res)
34 
35 # 解决办法:
36 res = time.mktime(ttp) # 变成时间戳
37 time_str = time.ctime(res) # 变成时间字符串;
38 print(time_str)
39 
40 #sleep()         程序睡眠等待
41 # time.sleep(2)
42 # print("我睡醒了")
43 
44 
45 
46 # 注意:=> strftime 时间元组 => 时间字符串 
47 # 4.strftime()      格式化时间字符串(格式化字符串,时间元组)
48 """linux支持中文显示,windows默认不支持"""
49 res = time.strftime("你好 :%Y-%m-%d %H:%M:%S ")
50 print(res)
51 
52 # 指定时间元组格式化字符串;
53 ttp = (2021,12,9,11,5,59,0,0,0)
54 res = time.strftime("你好 :%Y-%m-%d %H:%M:%S " , ttp)
55 print(res)
56 
57 # 注意:=> strptime 时间字符串 => 时间元组
58 # 5.strptime()      将时间字符串通过指定格式提取到时间元组中(时间字符串,格式化字符串) 
59 """字符串必须严丝合缝,不能随便加空格;否则报错"""
60 strvar1="著名的NBA球星霍华德的生日是2020年12月8号,在家里的泳池中下午15点30分40秒开派对"
61 strvar2="著名的NBA球星霍华德的生日是%Y年%m月%d号,在家里的泳池中下午%H点%M分%S秒开派对"
62 res = time.strptime(strvar1,strvar2)
63 print(res)
64 
65 
66 #perf_counter()  用于计算程序运行的时间 (了解)
67 startime = time.time()
68 # startime = time.perf_counter()
69 for i in range(10000000):
70     pass
71 endtime = time.time()
72 # endtime = time.perf_counter()
73 print("用的时间是{}".format(endtime-startime))
View Code

6、压缩模块zipfile (后缀为zip)

 1 import zipfile
 2 
 3 
 4 # 1.创建压缩包
 5 # (1)打开压缩包
 6 zf = zipfile.ZipFile("ceshi100.zip","w",zipfile.ZIP_DEFLATED)
 7 # zf.write(路径,别名)
 8 # (2)写入文件
 9 zf.write("/bin/chmod","chmod")
10 zf.write("/bin/cat","cat")
11 zf.write("/bin/chown","tmp/chown")
12 # (3)关闭文件
13 zf.close()
14 
15 
16 # 2.解压文件
17 zf = zipfile.ZipFile("ceshi100.zip","r")
18 # 解压所有 extractall(路径)
19 # zf.extractall("ceshi100")
20 zf.extract("cat","ceshi200")
21 zf.close()
22 
23 
24 # 3.查看压缩包 支持with语法 (自动实现close操作,不需要手动)
25 with zipfile.ZipFile("ceshi100.zip","r") as zf:
26     lst = zf.namelist()
27     print(lst)
28     
29     
30 # 4.追加文件
31 with zipfile.ZipFile("ceshi100.zip","a",zipfile.ZIP_DEFLATED) as zf:
32     zf.write("/bin/ln","ln")
View Code
 1 def progress(percent):
 2     # 如果传入的比例超过100% ,强制等于100%;
 3     if percent > 1:
 4         percent = 1
 5     strvar = int(50 * percent) * "#"
 6     print("\r[%-50s] %d%%" % (strvar , percent * 100),end="")
 7 
 8 recv_data = 0
 9 total = 1024
10 while recv_data < total:
11     # 延迟0.1秒
12     time.sleep(0.1)
13     recv_data += 100
14     # 比例 = 接受数据的大小  /  总大小 
15     percent = recv_data / total
16     # 把比例扔给progress,显示实际的进度条效果;
17     progress(percent)
进度条演示

7、OS模块  对系统进行操作

 1 import os
 2 #system()  在python中执行系统命令
 3 # os.system("touch 1.txt")
 4 # os.system("ipconfig")
 5 # os.system("ifconfig")
 6 
 7 #popen()   执行系统命令返回对象,通过read方法读出字符串
 8 # obj = os.popen("ifconfig")
 9 # res = obj.read()
10 # print(res)
11 
12 #listdir() 获取指定文件夹中所有内容的名称列表
13 lst = os.listdir(".")
14 print(lst)
15 
16 #getcwd()  获取当前文件所在的默认路径
17 # 路径
18 res = os.getcwd()
19 print(res)
20 
21 # 路径 + 文件
22 print(__file__)
23 
24 #chdir()   修改当前文件工作的默认路径
25 os.chdir("/home/wangwen/mysoft/")
26 # os.system("mkdir ceshi100")
27 os.system("rm -rf ceshi100")
28 
29 #environ   获取或修改环境变量
30 print(os.environ)
31 print(os.environ["PATH"])
32 os.environ["PATH"] += ":/home/wangwen/mysoft"
33 os.system("wangwen")
34 
35 
36 #--os 模块属性
37 #name 获取系统标识   linux,mac ->posix      windows -> nt
38 print(os.name)
39 
40 #sep 获取路径分割符号  linux,mac -> /       window-> \
41 res = "wangwen"+ os.sep + "notepad"
42 print(repr(res))
43 
44 #linesep 获取系统的换行符号  linux,mac -> \n    window->\r\n 或 \n
45 print(repr(os.linesep))
os模块操作
 1 import os
 2 os.chdir("/home/wangwen/mysoft/")
 3 
 4 os.mknod   创建文件 (windows目前版本还存在兼容性问题,等待版本迭代;)
 5 os.mknod("lianxi.py")
 6 os.remove  删除文件
 7 os.remove("lianxi.py")
 8 os.mkdir   创建目录(文件夹)
 9 os.mkdir("abc_ww")
10 os.rmdir   删除目录(文件夹)
11 os.rmdir("abc_ww")
12 os.rename  对文件,目录重命名
13 os.rename("lianxi1","lianxi2")
14 os.makedirs   递归创建文件夹
15 os.makedirs("a/b/c/d/e/f/g")
16 os.removedirs 递归删除文件夹(空文件夹)
17 os.removedirs("a/b/c/d/e/f/g")
os模块具有 新建/删除
 1 import os,time
 2 
 3 pathvar = "/mnt/hgfs/day17/abc.py"
 4 #basename() 返回文件名部分
 5 res = os.path.basename(pathvar)
 6 print(res)
 7 #dirname()  返回路径部分
 8 res = os.path.dirname(pathvar)
 9 print(res)
10 
11 print(__file__) # /mnt/hgfs/python33_gx/day17/3.py
12 res = os.path.dirname(__file__)
13 print(res)
14 
15 #split() 将路径拆分成单独的文件部分和路径部分 组合成一个元组
16 tup = os.path.split(pathvar)
17 print(tup)
18 
19 #join()  将多个路径和文件组成新的路径 可以自动通过不同的系统加不同的斜杠  linux / windows\
20 path1 = "home"
21 path2 = "wangwen"
22 path3 = "mysoft"
23 # 方法一
24 pathvar = path1 + os.sep + path2 + os.sep + path3
25 print(pathvar)
26 # 方法二(推荐)
27 pathvar = os.path.join(path1,path2,path3)
28 print(pathvar)
29 
30 #splitext() 将路径分割为后缀和其他部分 (了解)
31 pathvar = "/mnt/hgfs/.day17/abc.py"
32 res = os.path.splitext(pathvar)
33 print(res)
34 
35 res = pathvar.split(".")
36 print(res[-1])
37 
38 #getsize()  获取文件的大小 ***
39 """getsize只能获取文件大小,不能获取文件夹的大小"""
40 print(os.getcwd())
41 pathvar = os.path.join(os.getcwd(),"1.txt") # /mnt/hgfs/python33_gx/day17/1.txt
42 print(pathvar)
43 res = os.path.getsize(pathvar)
44 print(res)
45 
46 #isdir()    检测路径是否是一个文件夹 ***
47 pathvar = os.path.join(os.getcwd(),"1.txt") # /mnt/hgfs/python33_gx/day17/1.txt
48 res = os.path.isdir(pathvar)
49 print(res)
50 #isfile()   检测路径是否是一个文件 ***
51 res = os.path.isfile(pathvar)
52 print(res)
53 #islink()   检测路径数否是一个链接 **
54 res = os.path.islink("/home/wangwen/ceshi03/ceshi01")
55 print(res)
56 
57 
58 os.chdir("/home/wangwen/mysoft/")
59 """ stat 文件 => 查看相应的时间 """ 
60 #getctime() [windows]文件的创建时间,[linux]权限的改动时间(返回时间戳) **
61 res = os.path.getctime("ceshi2.py") 
62 print(res) 
63 #getmtime() 获取文件最后一次修改时间(返回时间戳) **
64 res = os.path.getmtime("ceshi2.py") 
65 print(res) 
66 #getatime() 获取文件最后一次访问时间(返回时间戳) **
67 res = os.path.getatime("ceshi2.py") 
68 print(res) 
69 # 返回时间字符串
70 str_time = time.ctime(res)
71 print(str_time)
72 
73 #exists()   检测指定的路径是否存在 ***
74 res = os.path.exists("ceshi4.py")
75 print(res)
76 
77 
78 
79 #isabs()    检测一个路径是否是绝对路径 ***
80 pathvar = "."
81 res = os.path.isabs(pathvar)
82 print(res)
83 
84 #abspath()  将相对路径转化为绝对路径 ***
85 res = os.path.abspath(pathvar)
86 print(res)
87 
88 # 如果不是绝对路径 => 变成绝对路径
89 """/开头的是绝对路径,剩下的都是相对路径;"""
90 pathvar = "ceshi3.py"
91 if not os.path.isabs(pathvar):
92     res = os.path.abspath(pathvar)
93     print(res)
os.path

 

8、shutil模块 复制/移动/

 1 # 1.复制内容
 2 # copyfileobj(fsrc, fdst[, length=16*1024])  复制文件 (length的单位是字符(表达一次读多少字符)) (了解)
 3 """
 4 fp1 = open("lianxi2",mode="r+",encoding="utf-8")
 5 fp2 = open("ceshi1.txt",mode="w",encoding="utf-8")
 6 shutil.copyfileobj(fp1,fp2)
 7 """
 8 # copyfile(src,dst)   #单纯的仅复制文件内容 , 底层调用了 copyfileobj  (了解)
 9 shutil.copyfile("ceshi1.txt","ceshi3.py")
10 
11 # 2.复制权限
12 # copymode(src,dst)   #单纯的仅复制文件权限 , 不包括内容  (虚拟机共享目录都是默认777)
13 """复制权限时,必须文件存在"""
14 shutil.copymode("ceshi3.py","lianxi2")
15 
16 # copystat(src,dst)   #复制所有状态信息,包括权限,组,用户,修改时间等,不包括内容
17 shutil.copystat("lianxi2","ceshi4.py")
18 
19 # 3.复制内容 + 权限
20 # copy(src,dst)       #复制文件权限和内容
21 shutil.copy("lianxi2","ceshi5.py")
22 
23 # copy2(src,dst)      #复制文件权限和内容,还包括权限,组,用户,时间等
24 shutil.copy2("lianxi2","ceshi6.py")
25 
26 # 4.递归拷贝/删除
27 # copytree(src,dst)   #拷贝文件夹里所有内容(递归拷贝)
28 shutil.copytree("ceshi777","ceshi666")
29 
30 # rmtree(path)        #删除当前文件夹及其中所有内容(递归删除)
31 shutil.rmtree("ceshi777")
32 
33 # 5.剪切
34 # move(path1,paht2)   #移动文件或者文件夹
35 shutil.move("ceshi1.txt","pycharm-community-2020.1.3/ceshi2.ttt")
View Code

 

 1 def getallsize(pathvar):
 2     size = 0
 3     lst = os.listdir(pathvar)
 4     for i in lst:
 5         # 拼接成完整的绝对路径
 6         pathnew = os.path.join(pathvar,i)
 7         if os.path.isdir(pathnew):
 8             # print("[文件夹]",i)
 9             size += getallsize(pathnew)
10         elif os.path.isfile(pathnew):
11             # print("[文件]",i)
12             size += os.path.getsize(pathnew)
13 
14     return size
15     
16 res = getallsize(pathvar)
17 print(res)
计算文件大小

 

9、tarfile 模块 后缀为.tar  |  .tar.gz  |   .tar.bz2

 1 import tarfile
 2 
 3 # ### 1.创建tar包
 4 # 1.创建压缩包
 5 tf = tarfile.open("ceshi1210.tar","w",encoding="utf-8")
 6 # 2.写入文件
 7 tf.add("/bin/cat","cat")
 8 tf.add("/bin/chacl","chacl")
 9 tf.add("/bin/cp","tmp/cp")
10 tf.add("/aaabbb","aaabbb") #可直接压缩文件夹
11 # 3.关闭文件
12 tf.close() # 225,280 
13 
14 # ### 2.创建.tar.gz包
15 tf = tarfile.open("ceshi1210.tar.gz","w:gz",encoding="utf-8")
16 tf.add("/bin/cat","cat")
17 tf.add("/bin/chacl","chacl")
18 tf.add("/bin/cp","tmp/cp")
19 tf.add("/aaabbb","aaabbb")
20 tf.close() # 96,797
21 
22 # ### 3.创建.tar.bz2包
23 tf = tarfile.open("ceshi1210.tar.bz2","w:bz2",encoding="utf-8")
24 tf.add("/bin/cat","cat")
25 tf.add("/bin/chacl","chacl")
26 tf.add("/bin/cp","tmp/cp")
27 tf.add("/aaabbb","aaabbb")
28 tf.close() # 84078
29 
30 # ### 解压文件
31 tf = tarfile.open("ceshi1210.tar.bz2","r",encoding="utf-8")
32 # 解压所有
33 # tf.extractall("ceshi1210")
34 # 解压单个(落脚在文件身上)
35 tf.extract("aaabbb/1.py","ceshi1210_1")
36 tf.close()
37 
38 # ### 查看文件 (使用with语法)
39 with tarfile.open("ceshi1210.tar.bz2","r",encoding="utf-8") as tf:
40     lst = tf.getnames()
41     print(lst)
42 
43 # ### 追加文件
44 """无法对已经压缩过的压缩包做内容的追加;"""
45 # with tarfile.open("ceshi1210.tar","a",encoding="utf-8") as tf:
46     # tf.add("/bin/mv","mv") # success 
47 
48 # with tarfile.open("ceshi1210.tar.bz2","a",encoding="utf-8") as tf:
49     # tf.add("/bin/mv","mv") # error
50 
51 # ### 解决办法:
52 """
53 1.先解压
54 2.将文件追加到该文件夹中
55 3.在重新过滤打包即可
56 """
57 import shutil,os
58 pathvar = os.getcwd()
59 print(pathvar) # /mnt/hgfs/python33_gx/day17/代码
60 pathvar1 = os.path.join(pathvar,"ceshi1210.tar.bz2") # /mnt/hgfs/python33_gx/day17/代码/ceshi1210.tar.bz2
61 pathvar2 = os.path.join(pathvar,"ceshi1210_2")
62 
63 
64 # 1.先解压文件
65 with tarfile.open(pathvar1,"r",encoding="utf-8") as tf:
66     tf.extractall("ceshi1210_2")
67 
68 # 2.将文件追加到该文件夹中
69 shutil.copy("/bin/nano",pathvar2)
70 
71 # 3.在重新过滤打包即可
72 """过滤掉cat,剩下的数据打包"""
73 lst = os.listdir(pathvar2)
74 print(lst) # ['aaabbb', 'cat', 'chacl', 'nano', 'tmp']
75 
76 
77 with tarfile.open(pathvar1,"w:bz2",encoding="utf-8") as tf:
78     for i in lst:
79         if i != "cat":
80             # 拼接好完整绝对路径
81             pathvar = os.path.join(pathvar2,i)
82             # 添加到压缩包中
83             tf.add(pathvar,i)
View Code

 

四、正则表达式

正则表达式由一些 [普通字符] 和一些 [元字符] 组成:
(1)普通字符包括大小写字母和数字
(2)元字符具有特殊含义,大体种类分为如下:

  1. .预定义字符集,字符组
  2. 量词
  3. 边界符
  4. 分组

语法: lst = re.findall("正则表达式","字符串")

1、匹配单个字符

1..预定义字符集

预定义字符集匹配内容
. 匹配任意字符,除了换行符\n
\d 匹配数字
\D 匹配非数字
\w 匹配字母或数字或下划线 (正则函数中,支持中文的匹配)
\W 匹配非字母或数字或下划线
\s 匹配任意的空白符
\S 匹配任意非空白符
\n 匹配一个换行符
\t 匹配一个制表符
[] 匹配中括号内列举的字符

 

 1 # \d 匹配数字
 2 lst = re.findall("\d","kjsdkfj2134*&(&你胜多负少")
 3 print(lst)
 4 
 5 # \D 匹配非数字
 6 lst = re.findall("\D","kjsdkfj2134*&(&你胜多负少")
 7 print(lst)
 8 
 9 # \w 匹配字母或数字或下划线     (正则函数中,支持中文的匹配)
10 lst = re.findall("\w","xboyww 1231 s撒旦法&*()J_H")
11 print(lst)
12 
13 # \W 匹配非字母或数字或下划线
14 lst = re.findall("\W","xboyww 1231 s撒旦法&*()J_H")
15 print(lst)
16 
17 # \s 匹配任意的空白符 (空格 \r \t \n )
18 lst = re.findall('\s',"    sdf            jkjk  \r ")
19 print(lst)
20 
21 # \S 匹配任意非空白符
22 lst = re.findall('\S',"    sdf            jkjk  \r ")
23 print(lst)
24 
25 # \n 匹配一个换行符
26 strvar = """
27 11122
28 """
29 lst = re.findall(r"\n",strvar)
30 print(lst)
31 
32 # \t 匹配一个制表符
33 strvar = """
34 11122                3434
35 """
36 lst = re.findall(r"\t",strvar)
37 print(lst)
View Code

2.字符组

字符组格式说明 [默认必须从字符组中选一个]
[...] 匹配字符组中的字符
[^...] 匹配除了字符组内所有内容,之外的所有字符

 

 1 lst = re.findall("[123]","abc1def2zzz3")
 2 print(lst)
 3 
 4 print(re.findall('a[abc]b','aab abb acb adb')) # aab abb acb
 5 
 6 print(re.findall('a[0123456789]b','a1b a2b a3b acb ayb')) # a1b a2b a3b
 7 # 优化写法 0123456789 => 0-9
 8 print(re.findall('a[0-9]b','a1b a2b a3b acb ayb'))  # ['a1b', 'a2b', 'a3b']
 9 
10 print(re.findall('a[abcdefg]b','a1b a2b a3b acb ayb adb')) # acb adb
11 # 优化写法 abcdefg => a-g 表达所有的小写字母 a-z
12 print(re.findall('a[a-g]b','a1b a2b a3b acb ayb adb')) 
13 print(re.findall('a[a-z]b','a1b a2b a3b acb ayb adb')) # acb ayb adb
14 
15 print(re.findall('a[ABCDEFG]b','a1b a2b a3b  aAb aDb aYb')) # aAb aDb
16 # 优化写法 ABCDEFG => A-G 表达所有的大写字母 A-Z
17 print(re.findall('a[A-G]b','a1b a2b a3b  aAb aDb aYb'))
18 print(re.findall('a[A-Z]b','a1b a2b a3b  aAb aDb aYb')) # aAb aDb aYb
19 
20 print(re.findall('a[0-9a-zA-Z]b','a-b aab aAb aWb aqba1b'))  #  aab aAb aWb  aqb a1b
21 # 注意点 不能写0-z表达所有的字母+数字 会含有特殊字符
22 print(re.findall('a[0-z]b','a-b aab aAb aWb aqba1b a@b'))  #  aab aAb aWb  aqb a1b a@b
23 
24 print(re.findall('a[0-9][*#/]b','a1/b a2b a29b a56b a456b')) # a1/b
25 
26 # ^ 在字符组当中,表达除了...的意思 , 
27 print(re.findall('a[^-+*/]b',"a%b ccaa*bda&bd")) #  a%b a&b
View Code

3.注意点

无论是正则表达式,还是后面字符串,前面写r一定不错

# 匹配 ^ - \
strvar = "a^c a-c a\c"
lst = re.findall(r"a[\^\-\\]c",strvar)
print(lst)
print(lst[-1])

# \b 退格的意思(正则中还有边界符的含义 \b同时具有2层含义)
lst = re.findall(r"a\\b",r"a\b")
# print("a\b")
print(lst)

 

2、多个字符匹配

1.量词

量词用法说明
? 重复0次或1次
+ 重复1次或多次 (至少1次)
* 重复0次或多次 (任意次)
{n} 重复n次
{n,} 重复n次或更多次 (至少n次)
{n,m} 重复n到m次
.* .+ 贪婪模式匹配
.*? .+? 非贪婪模式匹配
 1 '''1) ? 匹配0个或者1个a '''
 2 print(re.findall('a?b','abbzab abb aab'))  # ab b ab ab b ab
 3 '''2) + 匹配1个或者多个a '''
 4 print(re.findall('a+b','b ab aaaaaab abb')) # ab aaaaaab ab
 5 '''3) * 匹配0个或者多个a '''
 6 print(re.findall('a*b','b ab aaaaaab abbbbbbb')) # b ab aaaaaab ab b b b b b b
 7 '''4) {m,n} 匹配m个至n个a ''' # 1 <= a <= 3
 8 print(re.findall('a{1,3}b','aaab ab aab abbb aaz aabb')) # aaab ab aab ab aab
 9 # a字符出现的次数是必须2次
10 print(re.findall('a{2}b','aaab ab aab abbb aaz aabb')) # aab aab aab
11 # a字符出现的次数至少2次
12 print(re.findall('a{2,}b','aaab ab aab abbb aaz aabb')) # aaab aab aab
View Code

2.贪婪匹配 与 非贪婪匹配 [语法:量词的后面加?号]

贪婪模式 : 默认向更多次匹配
回溯算法 : 从左向右一直匹配,直到匹配不到了,在回头,把上一次找到的元素返回;

非贪婪模式 : 默认向更少次匹配

 1 strvar = "刘能和刘老根和刘一手111子222子"
 2 lst = re.findall("刘.",strvar) # 刘能 刘老 刘一
 3 print(lst)
 4 
 5 lst = re.findall("刘.?",strvar) # 刘能 刘老 刘一
 6 print(lst)
 7 
 8 lst = re.findall("刘.+",strvar) # 刘能和刘老根和刘一手111子222子
 9 print(lst)
10 
11 lst = re.findall("刘.*",strvar) # 刘能和刘老根和刘一手111子222子
12 print(lst)
13 
14 lst = re.findall("刘.{1,30}",strvar) # 刘能和刘老根和刘一手111子222子
15 print(lst)
16 
17 lst = re.findall("刘.{1,30}子",strvar) # 刘能和刘老根和刘一手111子222子
18 print(lst)
贪婪模式
 1 lst = re.findall("刘.??",strvar) # ['刘', '刘', '刘']
 2 print(lst)
 3 
 4 lst = re.findall("刘.+?",strvar) # 刘能 刘老 刘一
 5 print(lst)
 6 
 7 lst = re.findall("刘.*?",strvar) # ['刘', '刘', '刘']
 8 print(lst)
 9 
10 lst = re.findall("刘.{1,30}?",strvar) # 刘能 刘老 刘一
11 print(lst)
12 
13 lst = re.findall("刘.{1,30}?子",strvar) # 刘能和刘老根和刘一手111子
14 print(lst)
非贪婪模式

 

3.边界符 \b

只要不是字母数字下划线都可以作为边界;
\b
(1) 转义字符 退格
(2) 正则中的边界符

  1. 卡住左边界: \bw
  2. 卡住右边界: d\b
# 卡住右边界
strvar = "word pwd book"
lst = re.findall(r"d\b",strvar)
lst = re.findall(r".*d\b",strvar)
lst = re.findall(r".*?d\b",strvar)
print(lst)

# 卡住左边界
strvar = "pwd word book"
lst = re.findall(r"\bw",strvar) # ['w']
lst = re.findall(r"\bw.*",strvar) # ['word pwd book']
lst = re.findall(r"\bw.*?",strvar) # ['w']
lst = re.findall(r"\bw.*? ",strvar) # ['w']
lst = re.findall(r"\bw\S*",strvar) # ["word"]
print(lst)

4. ^ 匹配字符串的开始  $匹配字符串的结尾

如果使用了^ 和 $ 必须要把字符串看成一个整体

 1 strvar = "大哥大嫂大爷"
 2 print(re.findall('大.',strvar))  # ['大哥', '大嫂', '大爷']
 3 print(re.findall('^大.',strvar)) # 大哥
 4 print(re.findall('大.$',strvar)) # 大爷
 5 print(re.findall('^大.$',strvar)) # []
 6 print(re.findall('^大.*?$',strvar))# 大哥大嫂大爷
 7 print(re.findall('^大.*?大$',strvar)) # []
 8 print(re.findall('^大.*?爷$',strvar)) # 大哥大嫂大爷
 9 
10 print(re.findall('^g.*? ' , 'giveme 1gfive gay')) #giveme 
11 print(re.findall('five$' , 'aassfive')) # five
12 print(re.findall('^giveme$' , 'giveme')) # giveme
13 print(re.findall('^giveme$' , 'giveme giveme')) # []
14 print(re.findall('giveme' , 'giveme giveme')) # giveme giveme
15 print(re.findall("^g.*e",'giveme 1gfive gay')) # giveme 1gfive
View Code

3、匹配分组 ()表达一个整体

1、匹配分组 ()

print(re.findall('.*?_good','wusir_good alex_good secret男_good'))#['wusir_good', ' alex_good', ' secret男_good']
# findall  会优先显示括号里面的内容
print(re.findall('(.*?)_good','wusir_good alex_good secret男_good'))#['wusir', ' alex', ' secret男']
# findall  ?: 取消优先显示括号的功能
print(re.findall('(?:.*?)_good','wusir_good alex_good secret男_good'))#['wusir_good', ' alex_good', ' secret男_good']

2、|的使用

lst = re.findall("a|b","sdhfjha234234bkjkjk")
print(lst) # ['a', 'b']

# 注意点: 把较难匹配的内容放到前面,容易匹配的内容放到后面,才能保证所有元素都能匹配到;
lst = re.findall("abc|abcd","12342abcdjskdfjkabc")
print(lst) # ["abc","abc"]
lst = re.findall("abcd|abc","12342abcdjskdfjkabc")
print(lst) # ['abcd', 'abc'

3、search

obj.group() => 获取匹配到的内容
obj.groups() => 获取分组中的内容

findall : 优点:从左到右匹配,找到所有的内容,返回到列表
缺点:匹配的内容和分组的内容不能同时显示在同一个界面中

search : 缺点:从左到右匹配,匹配到第一个满足条件的内容直接返回,最后返回的是对象
优点:可以把分组里的内容和匹配到的内容同时显示在同一个界面中

obj = re.search("(www)\.(baidu|oldboy)\.(com)",strvar)
print(obj)
# 获取匹配到的内容
res = obj.group()
print(res)
# 获取分组中的内容
# 方法一 (推荐)
res = obj.groups()
print(res)
# 方法二
res = obj.group(1)
print(res)
res = obj.group(2)
print(res)
res = obj.group(3)
print(res)

 

4、反向引用

# 把第一个括号里面的数据放到\1在引用一次;
obj = re.search(r"<(.*?)>(.*?)<(/\1)>",strvar)
print(obj)
print(obj.group())
print(obj.groups())

strvar = "a1b2cab z4y5gzy"
obj = re.search(r"(.*?)\d(.*?)\d(.*?)(\1)(\2)",strvar)
print(obj.group()) # a1b2cab
print(obj.groups())

5、命名分组

?P<组名>正则表达式) 给这个组起一个名字

(?P=组名) 引用之前组的名字,把该组名匹配到的内容放到当前位置

# 方法一
obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)(\1)(\2)",strvar)
print(obj)
print(obj.group())
print(obj.groups())

# 方式二
obj = re.search(r"(?P<tag1>.*?)\d(?P<tag2>.*?)\d(?P<tag3>.*?)(?P=tag1)(?P=tag2)",strvar)
print(obj)
print(obj.group())
print(obj.groups())

6、正则函数

1.search

通过正则匹配出第一个对象返回,通过group取出对象中的值 ,通过groups取出分组当中的数据

2.match

search 和 match 使用时一模一样,区别在于在search正则表达式的开头加上^ 等价于 match 

3.split 切割

strvar = "alex2674623wusir22xboyww55555risky"
res = re.split("\d+",strvar)
print(res)

4.sub      替换 

sub(正则表达式,替换的元素,替换的原字符串[,替换的次数])

strvar = "alex_wusir|xboyww&risky"
res = re.sub("[_|&]","@",strvar,2)
print(res)

subn     替换

subn 对比 sub 只是在返回值有所不同,返回的是元组(字符串,替换次数)

strvar = "alex_wusir|xboyww&risky"
res = re.subn("[_|&]","@",strvar)
print(res) # ('alex@wusir@xboyww@risky', 3)

5、finditer 匹配字符串中相应内容,返回迭代器

from collections import Iterator,Iterable
strvar = "sdf234sdfjkhj&^&*^987"
it = re.finditer("\d",strvar)
print(isinstance(it,Iterator))
for i in it:
    # print(i)
    print(i.group())

6、compile 指定一个统一的匹配规则

可以制定一次正则表达式,编译一次,终身受益,不需要反复编译,提升执行效率

pattern = re.compile("\d")
print(pattern)
strvar = "sdf234sdfjkhj&^&*^987"
# search的使用
obj = pattern.search(strvar)
print(obj.group())
# findall的使用
res = pattern.findall(strvar)
print(res

7、修饰符

常用修饰符说明
re.I 使匹配对大小写不敏感
re.M 使每一行都能够单独匹配(多行匹配),影响 ^ 和 $
re.S 使 . 匹配包括换行在内的所有字符

 

 1 # (1) re.I 使匹配对大小写不敏感
 2 strvar = "<h1>我是大标题</h1>"
 3 pattern = re.compile("<h1>(.*?)</H1>" , flags = re.I)
 4 obj = pattern.search(strvar)
 5 print(obj)
 6 print(obj.group())
 7 print(obj.groups())
 8 
 9 # (2) re.M 使每一行都能够单独匹配(多行匹配),影响 ^ 和 $
10 strvar = """
11 <a>我是连接</a>
12 <p>我是段落</p>
13 <div>我是盒子</div>
14 """
15 
16 pattern = re.compile("^<.*?>.*?<.*?>$",flags = re.M)
17 lst = pattern.findall(strvar)
18 print(lst)
19 # print(obj)
20 # print(obj.group())
21 
22 
23 # (3) re.S 使 . 匹配包括换行在内的所有字符
24 strvar = """
25 please give 
26 234234mefive
27 """
28 pattern = re.compile(".*?mefive" , flags=re.S)
29 obj = pattern.search(strvar)
30 print(obj)
31 print(obj.group()) # 234234mefive
View Code

(扩展) 如果想要所有的修饰符 使用 | 进行拼接

pattern = re.compile(".*?mefive" , flags=re.S|re.M|re.I)
obj = pattern.search(strvar)
print(obj)

 

posted @ 2020-12-17 22:35  讷言敏行~  阅读(120)  评论(0编辑  收藏  举报