Python 第三节(正则表达式)

Python 第三节

@Jack_bin

python 3 字符串格式化

字符串格式化

Python的字符串格式化有两种方式: 百分号方式、format方式

%的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存。[PEP-3101]

This PEP proposes a new system for built-in string formatting operations, intended as a replacement for the existing ‘%’ string formatting operator.

1、百分号方式

%[(name)][flags][width].[precision]typecode
  • (name) 可选,用于选择指定的key
  • flags 可选,可供选择的值有:
    • + 右对齐;正数前加正好,负数前加负号;
    • - 左对齐;正数前无符号,负数前加负号;
    • 空格 右对齐;正数前加空格,负数前加负号;
    • 0 右对齐;正数前无符号,负数前加负号;用0填充空白处
  • width 可选,占有宽度
  • .precision 可选,小数点后保留的位数
  • typecode 必选
    s,获取传入对象的__str__方法的返回值,并将其格式化到指定位置
    r,获取传入对象的__repr__方法的返回值,并将其格式化到指定位置
    c,整数:将数字转换成其unicode对应的值,10进制范围为 0 <= i <= 1114111(py27则只支持0-255);字符:将字符添加到指定位置
    o,将整数转换成 八 进制表示,并将其格式化到指定位置
    x,将整数转换成十六进制表示,并将其格式化到指定位置
    d,将整数、浮点数转换成 十 进制表示,并将其格式化到指定位置
    e,将整数、浮点数转换成科学计数法,并将其格式化到指定位置(小写e)
    E,将整数、浮点数转换成科学计数法,并将其格式化到指定位置(大写E)
    f, 将整数、浮点数转换成浮点数表示,并将其格式化到指定位置(默认保留小数点后6位)
    F,将整数、浮点数转换成浮点数表示,并将其格式化到指定位置(默认保留小数点后6位)
    g,自动调整将整数、浮点数转换成 浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是e;)
    G,自动调整将整数、浮点数转换成 浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是E;)
    %,当字符串中存在格式化标志时,需要用 %%表示一个百分号
  • ==注:==Python中百分号格式化是不存在自动将整数转换成二进制表示的方式

常用格式化

tpl = "i am %s" % "xinlan"
 
tpl = "i am %s age %d" % ("xinlan", 18)
 
tpl = "i am %(name)s age %(age)d" % {"name": "xinlan", "age": 18}
 
tpl = "percent %.2f" % 99.97623
 
tpl = "i am %(pp).2f" % {"pp": 123.425556, }
 
tpl = "i am %(pp).2f %%" % {"pp": 123.425556, }

2、Format方式

[[fill]align][sign][#][0][width][,][.precision][type]
  • fill 【可选】空白处填充的字符
  • align 【可选】对齐方式(需配合width使用)
    <,内容左对齐
    >,内容右对齐(默认)
    ,内容右对齐,将符号放置在填充字符的左侧,且只对数字类型有效。 即使:符号+填充物+数字
    ^,内容居中
  • sign 【可选】有无符号数字
    +,正号加正,负号加负;
    -,正号不变,负号加负;
    空格 ,正号空格,负号加负;
  • # 【可选】对于二进制、八进制、十六进制,如果加上#,会显示 0b/0o/0x,否则不显示
  • 【可选】为数字添加分隔符,如:1,000,000
  • width 【可选】格式化位所占宽度
  • .precision 【可选】小数位保留精度
  • type 【可选】格式化类型
    • 传入” 字符串类型 “的参数
      s,格式化字符串类型数据
      空白,未指定类型,则默认是None,同s
    • 传入“ 整数类型 ”的参数
      b,将10进制整数自动转换成2进制表示然后格式化
      c,将10进制整数自动转换为其对应的unicode字符
      d,十进制整数
      o,将10进制整数自动转换成8进制表示然后格式化;
      x,将10进制整数自动转换成16进制表示然后格式化(小写x)
      X,将10进制整数自动转换成16进制表示然后格式化(大写X)
    • 传入“ 浮点型或小数类型 ”的参数
      e, 转换为科学计数法(小写e)表示,然后格式化;
      E, 转换为科学计数法(大写E)表示,然后格式化;
      f , 转换为浮点型(默认小数点后保留6位)表示,然后格式化;
      F, 转换为浮点型(默认小数点后保留6位)表示,然后格式化;
      g, 自动在e和f中切换
      G, 自动在E和F中切换
      %,显示百分比(默认显示小数点后6位)

常用格式化:

tpl = "i am {}, age {}, {}".format("seven", 18, 'xinlan')
  
tpl = "i am {}, age {}, {}".format(*["seven", 18, 'xinlan'])
  
tpl = "i am {0}, age {1}, really {0}".format("seven", 18)
  
tpl = "i am {0}, age {1}, really {0}".format(*["seven", 18])
  
tpl = "i am {name}, age {age}, really {name}".format(name="seven", age=18)
  
tpl = "i am {name}, age {age}, really {name}".format(**{"name": "seven", "age": 18})
  
tpl = "i am {0[0]}, age {0[1]}, really {0[2]}".format([1, 2, 3], [11, 22, 33])
  
tpl = "i am {:s}, age {:d}, money {:f}".format("seven", 18, 88888.1)
  
tpl = "i am {:s}, age {:d}".format(*["seven", 18])
  
tpl = "i am {name:s}, age {age:d}".format(name="seven", age=18)
  
tpl = "i am {name:s}, age {age:d}".format(**{"name": "seven", "age": 18})
 
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
 
tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2)
 
tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15)
 
tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)

更多格式化操作,请点击这里

迭代器和生成器

1、迭代器

迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件

特点:

1.访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
2.不能随机访问集合中的某个值 ,只能从头到尾依次访问访问到一半时不能往回退
3.便于循环比较大的数据集合,节省内存

>>> a = iter([1,2,3,4,5])
>>> a
<list_iterator object at 0x101402630>
>>> a.__next__()
>>> a.__next__()
>>> a.__next__()
>>> a.__next__()
>>> a.__next__()
>>> a.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

2、生成器

一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);如果函数中包含yield语法,那这个函数就会变成生成器;

def func():
    yield 1
    yield 2
    yield 3
    yield 4

上述代码中:func是函数称为生成器,当执行此函数func()时会得到一个迭代器。

>>> temp = func()
>>> temp.__next__()
>>> temp.__next__()
>>> temp.__next__()
>>> temp.__next__()
>>> temp.__next__()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

3、实例

a.利用生成器自定义range

def nrange(num):
    temp = -1
    while True:
        temp = temp + 1
        if temp >= num:
            return
        else:
            yield temp

b.利用迭代器访问range

py3图片转字符画.py:

# Author: Jack_Bin

from PIL import Image   #pip 下载 pillow库


#注意,win10系统不要用记事本打开,会乱码,建议使用Notpad++或者pycharm打开最后的txt文件

image_file = Image.open(rb"C:\Users\Administrator\Pictures\10.jpg")   #在指定目录下打开10.jpg  “rb” 二进制方式读取
image_file = image_file.resize((int(image_file.size[0]*0.3),int(image_file.size[1]*0.15)))   #缩放
count = '''$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~<>i!lI;:,\"^`'. '''  #用69个字符构图
p = len(count)
 #print(p)   69个

def objec(image_file):         #定义函数objec方法
    image_file = image_file.convert("L")    #将RGB图片转换为黑白图片
    output = ""    #创建一个空变量备用
    for h in range(0, image_file.size[1]):   ## 利用for循环,遍历y轴的各个像素值
        for w in range(0,image_file.size[0]):   ##--sine-- , 遍历x轴的各个像素值

            gray = image_file.getpixel((w,h))     ##计算灰度值
            output += count[int(p*gray/256)]     ##将256个灰度值映射到69个字符上,并加入到备用变量之中

        output += "\n"   # 遍历完一行像素后换行
    return output   #将函数方法的值——(变量最后的结果)返回

tmp = objec(image_file)   #创建实例运行objec函数方法
text = open(r'C:\Users\Administrator\Desktop\测试.txt',"w")  #在指定目录写入一个测试.txt文件(注意,是覆盖写入)
text.write(tmp)    #将返回的变量中的数据写入到“测试.txt ” 中
text.close()  #最后关闭程序,退出

早上9点到现在,就学会这么点东西 /捂脸

Python 使用递归斐波那契数列

以下代码使用递归的方式来生成斐波那契数列(即为,将函数的值代入函数内进行循环运算):

实例(Python 3.0+)

def recur_fibo(n):
   """递归函数
   输出斐波那契数列"""
   if n <= 1:
       return n
   else:
       return(recur_fibo(n-1) + recur_fibo(n-2))
 
 
# 获取用户输入
nterms = int(input("您要输出几项? "))
 
# 检查输入的数字是否正确
if nterms <= 0:
   print("输入正数")
else:
   print("斐波那契数列:")
   for i in range(nterms):
       print(recur_fibo(i))

执行以上代码输出结果为:

您要输出几项? 10
斐波那契数列:
0
1
1
2
3
5
8
13
21
34

在这里插入图片描述
2048小游戏.py

 # Author: Jack_Bin
# -*- coding:utf-8 -*
import random        #导入随机函数
import pygame        #导入pygame游戏模块
import sys           #导入系统模块

#创造一个矩形类   初始化这个类,类的初始属性有行和列
class Square:
    row = 0
    col = 0
    def __init__(self,row,col):
        self.row = row
        self.col = col

pygame.init()    #初始化pygame
pygame.mixer.init()  #初始化pygame的声音模块
pygame.time.delay(1000) #延迟1s
pygame.mixer.music.load("bgm.mp3")  #载入背景音乐
s = pygame.mixer.Sound("biu.wav")  # 载入音效biu
pygame.mixer.music.play(-1)   #循环播放背景音乐,这一句才开始播放,前面只是载入


w = 720    #设定窗口宽度为720
h = 720    #设定窗口高度为720
Row = 4    #设定总行数为4
Col = 4    #设定列数为4

greycolor = (30,30,30)    #设置边框颜色  灰色
textcolor = (0,0,0)       #设置文字颜色  黑色

screen = pygame.display.set_mode((w,h))  #定义屏幕舞台
pygame.display.set_caption("2048小游戏")       #设置标题为2048
fps = 20                                 #设置帧率为20
fclock = pygame.time.Clock()             #定义一个时钟变量

text =  pygame.font.Font("C:/Windows/Fonts/simsun.ttc",50)  #载入字体  宋体,同时设置文字大小为50


#初始化 二维列表
grid_value = [
    [0,0,0,0],
    [0,0,0,0],
    [0,0,0,0],
    [0,0,0,0]
]


#创建一个函数1   transfer   把一个含有0的列表变成一个不含0的列表
#例如  输入为 a = [2,0,0,4]
#      函数输出为 [2,4]
def transfer_nozero_list(list):      #输入为 一个列表,用list指示
    if(len(list)):          # 如果这个列表不为空
        newlist = []        # 新建一个新列表   newlist
        for ele in list:    #循环获得 list中的所有元素
            if(ele!=0):     # 如果 list中的元素不为0
                newlist.append(ele) #把这个元素添加到新列表  newlist中
        return newlist          #循环完之后,输出(返回)newlist
    else:
        return []           #如果列表为空,这输出一个空列表



#创建一个函数2   sum   计算一个列表中的任意相邻2个数的和
#要求 输入的列表必须是一个非零的列表  如[2,4]   不能是[2,0,4]
#例子 输入为 [4,2] 输出依然是[4,2]
#例子2 输入为[2,2,4] 输出为 [4,4]
#例子3 输入为[2,2,4,4] 输出为 [4,8]
def sum_of_every_2_number(nozerolist):    # 输入为列表    非零列表
    if(len(nozerolist)==0):         #如果列表为空
        return []                   #返回一个空列表
    elif(len(nozerolist)==1):       # 如果列表长度为1
        return nozerolist           # 则返回列表本身
    elif(len(nozerolist)==2):       #如果列表长度为2
        if (nozerolist[0] == nozerolist[1]):        #如果2个值相同
            return [nozerolist[0]+nozerolist[0]]    #返回他们的和,作为一个量,并返回为列表的形式。      例如 [2,2] 返回[4]而不是4
        else:                                       #如果2个值不同
            return nozerolist                       #返回原列表
    if(len(nozerolist)>2):          #如果列表长度大于2,这里要通过递归函数来实现所有相邻数的判断,不清楚递归函数的,需要先理解递归函数
        if(nozerolist[0]==nozerolist[1]):       #如果第一项和第二项相等
            nozerolist[0] = nozerolist[0] +nozerolist[0]        #第一项的值等于,第一项+第二项
            return [nozerolist[0]] + sum_of_every_2_number(nozerolist[2:])  #递归,返回列表[第一项,sum(原列表移除前2项)]
        else:                                   #如果第一项和第二项不相等
            return [nozerolist[0]] + sum_of_every_2_number(nozerolist[1:])  #递归,返回列表 [第一项,sum(原列表移除前1项)]

#创建一个函数3  output 得到一个列表的输出结果
#例子输入为 [2,0,0,4] 输出应该为[2,4,0,0]
#例子输入为 [2,2,0,4] 输出应该为[4,4,0,0]
#例子输入为 [2,2,4,4] 输出应该为[4,8,0,0]
def get_output_list_of_one_list(newlist):
    output_list = [0,0,0,0]       #初始定义一个输出列表
    if (len(newlist) != 0):       #如果列表非空
        if (len(transfer_nozero_list(newlist)) != 0):   #如果列表移除0之后也是非空,也就是排除[0,0,0,0]这种情况
            output = sum_of_every_2_number(transfer_nozero_list(newlist))   #输出为  函数2(函数1(列表))
            for i in range(len(output)):   # 循环所有output列表中的所有元素(遍历)
                output_list[i] += output[i] # 对应位置的值赋给新列表对应位置,这一句话可以在复制结果的同时保证列表后面0的完整性
    return output_list   #输出最后结果


#创建最重要的函数,函数4计算整个二维列表
#输入1 二维列表数据,grid
#输入2 方向   上、下、左、右
# [0,0,0,0]             [0,0,0,0]
# [0,2,0,0]  向下移动   [0,0,0,0]
# [2,0,0,0]    ------    [0,0,0,0]
# [2,2,4,4]             [4,4,4,4]
def cal_grid_value(grid_value,direction):   #输入变量1 grid,变量2 方向
    output_grid = []                #初始化二维列表
    if(direction == 'left' or direction == 'right'):   #方向是←或者→
        for x in range(4):     #循环取出二维列表的4个列表
            list = grid_value[x]     #4个子列表保存成新的列表 list
            output_list = [0, 0, 0, 0]   #初始化输出新列表
            if (direction == 'left'):       #如果方向为←
                output_list = get_output_list_of_one_list(list)   #新列表 = 函数3(子列表)
                output_grid.append(output_list)                   #输出二维列表 添加一个项目,项目内容为新列表output_list,循环4次就可以得到完整的二维列表
            elif(direction == 'right'):     #如果方向为→
                newlist = list.copy()       #把列表复制一下,不能用等于,要用深拷贝copy。记住涉及到底层数据结构
                newlist.reverse()           #把列表倒过来,即原来的[2,4,8,16] 变为[16,8,4,2] 可以理解为翻转180度
                output_list = get_output_list_of_one_list(newlist)   #这里与←移相同
                output_list.reverse()       #把输出结果在颠倒一次,切记处理前颠倒一次,处理后还要颠倒一次
                output_grid.append(output_list) #得到输出
    elif(direction == 'up' or direction == 'down'):             #如果方向是↑或者↓,这里就需要顺时针或者逆时针旋转90度
        grid_buffer = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]     #初始化一个缓冲二维列表
        output_grid = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]     #初始化一个缓冲输出二维列表
        output_grid_buffer = []  #初始化输出列表
        if(direction == 'up'):   #如果方向是↑,就是先把二维列表逆时针旋转90度,然后转化为向←移动,之后再顺时针旋转90度

            # 此处表示逆时针旋转90度,为什么?  自己画图然后写上每个点坐标,分析即可得到
            for x in range(4):
                for y in range(4):
                    grid_buffer[x][y] = grid_value[y][3-x]

            #这里与←移那部分完全相同
            for x in range(4):
                list = grid_buffer[x]
                output_list = [0, 0, 0, 0]
                output_list = get_output_list_of_one_list(list)
                output_grid_buffer.append(output_list)

            # 此处表示顺时针旋转90度,为什么?  自己画图然后写上每个点坐标,分析即可得到
            for x in range(4):
                for y in range(4):
                    output_grid[x][y] = output_grid_buffer[3-y][x]
        else:   #如果方向是↓,就是先把二维列表顺时针旋转90度,然后转化为向←移动,之后再逆时针旋转90度

            # 此处表示顺时针旋转90度,为什么?  自己画图然后写上每个点坐标,分析即可得到
            for x in range(4):
                for y in range(4):
                    grid_buffer[x][y] = grid_value[3-y][x]
            # 这里与←移那部分完全相同
            for x in range(4):
                list = grid_buffer[x]
                output_list = [0, 0, 0, 0]
                output_list = get_output_list_of_one_list(list)
                output_grid_buffer.append(output_list)
            # 此处表示逆时针旋转90度,为什么?  自己画图然后写上每个点坐标,分析即可得到
            for x in range(4):
                for y in range(4):
                    output_grid[x][y] = output_grid_buffer[y][3-x]
    return output_grid    # 返回最后的二维列表


#创建函数5,对于一个存在的表格,在剩余的位置随机生成一个数字,2或者4,2的概率为70%,4的概率为30%
# [0,0,0,0]
# [0,2,0,0]    只能在0的位置出现,不能在已经有数字的位置出现
# [2,0,0,0]       问题1,如何得到70%和30%的概率,非常简单用 random.random()<0.7即可
# [2,2,4,4]       问题2,如何随机位置,非常简单用 int(random.random()*len(list))即可
def create_new_value(grid):  #输入为一个二维列表
    zero_position_list = []     #定义一个列表用来保存所有为0 的位置

    #两重循环,得到所有0的位置
    for x in range(4):
        for y in range(4):
            if(grid[x][y]==0): #如果值为0
                zero_position_list.append([x,y])  #存进列表中
    #随机生成位置
    position = int(random.random()*len(zero_position_list))

    value = 4 if(random.random()>0.7) else 2   #70% 和 30% 概率,是if else的更加高级写法,可以不这样写,此处为了节省空间
    grid[zero_position_list[position][0]][zero_position_list[position][1]] = value    #把2或者4,赋值到指定位置去,主要有position确定
    return grid  #返回最后二维列表


#创建绘图函数    绘制一个矩形窗口
#例如  grid(Square(0,1),greycolor,2) 就是在row=0  col=1这个位置,绘制一个边框为灰色的矩形方块, 数字内容为2
#这里的输入有3个参量,square是前面定义的square类,用来确定生成位置的
#  bordercolor 变量为边框的颜色
#  value 是填充数字内容的文字,2 4 8 16 32 64 128 256 512 1024 2048 .......
#   不同value可以设置不同的背景颜色,背景颜色具体设置在函数内
def grid(square,bordercolor,value):
    cell_width = w/Col          #计算矩形的宽度
    cell_height = h/Row         #计算矩形的高度
    left = square.col*cell_width    #计算矩形的顶点坐标 左边
    top = square.row*cell_height    #计算矩形的顶点坐标 顶部
    bgcolor = (255,255,255)         #设置默认背景颜色,白色

    #这里一大段都是定义颜色,不同数字不同颜色
    if(value==0):
        bgcolor = (255,255,255)
    elif(value==2):
        bgcolor = ( 255, 182, 193)   #Lemon
    elif (value == 4):
        bgcolor = ( 0,191,255)  #SkyBlue
    elif (value == 8):
        bgcolor = (0,255,127)  # SpringGreen
    elif (value == 16):
        bgcolor = ( 255,215,0)  # Gold
    elif (value == 32):
        bgcolor = (255,127,80)  # Coral
    elif (value == 64):
        bgcolor = (65,105,225)  # RoyalBlue
    elif (value == 128):
        bgcolor = (238,130,238)  # 紫罗兰
    elif (value == 256):
        bgcolor = (95,158,160)  # 军校蓝
    elif (value == 512):
        bgcolor = (255,140,0)  # DarkOrange
    elif (value == 1024):
        bgcolor = (255, 182, 193)  # pink
    elif (value == 2048):
        bgcolor = ( 0,206,209)  # 绿宝石
    else:
        bgcolor = (200, 200, 200)  # grey


    pygame.draw.rect(screen,bordercolor,(left,top,cell_width,cell_height),2)    # 绘制边框
    pygame.draw.rect(screen,bgcolor,(left+2,top+2,cell_width-3,cell_height-3),0)    #绘制实心矩形
    text_ft = text.render(str(value), 1, textcolor)                             # 定义文字变量

    #文字为一位,两位,三位,四位时候不同的横坐标偏移
    if(value<10):
        leftgap = 10
    elif(value<100):
        leftgap = 20
    elif (value < 1000):
        leftgap = 35
    else:
        leftgap = 50
    screen.blit(text_ft, (left+int(cell_width/2)-leftgap, top+int(cell_height/2)-20))  #绘制最终文本
    pass


#创建更加完整的绘图函数   从一个矩形,绘制出4*4的矩形窗格
#输入只需要二维数组列表
def draw_grid(datalist):

    #二重循环取出二维列表的所有元素,调用绘制一个矩形的函数
    for row in range(4):
        for col in range(4):
            grid(Square(row,col),greycolor,datalist[row][col])



#绘制一个全新的窗口
new_grid = create_new_value(grid_value)

#主程序循环主体
while True:

    #所有的按键事件
    for event in pygame.event.get():    #响应所有的事件
        direction = ''   #初始化方向变量,变量值为空
        if (event.type == pygame.QUIT):  # 接收到退出事件后退出程序
            sys.exit()   #关闭程序
        elif(event.type == pygame.KEYDOWN): #接收到方向键
            if (event.key ==pygame.K_LEFT):  #如果方向键←被按下
                direction = 'left'   #设定方向为←
            elif(event.key == pygame.K_RIGHT):#如果方向键→被按下
                direction = 'right'  #设定方向为→
            elif (event.key == pygame.K_UP):#如果方向键↑被按下
                direction = 'up'    #设定方向为↑
            elif (event.key == pygame.K_DOWN):#如果方向键↓被按下
                direction = 'down'  #设定方向为↓
            else:   #其他按键被按下
                direction = 'unknown'   #设定方向为不知道
            if(direction!= '' and direction!= 'unknown'):  #如果方向   不为空,也不为不知道,那就一定是上下左右被按下了
                s.play()  # 播放1次音效biu
                new_grid_buffer = cal_grid_value(new_grid, direction)    #调用函数计算按下方向键之后新的二维列表的值
                if (new_grid == new_grid_buffer):           #如果按下方向之后,二维列表没有变化,也就是这个方向没有作用
                    draw_grid(new_grid)         #重新绘制一下界面
                else:#如果按下方向之后,二维列表有变化,也就是这个方向有作用,那么久应该新生成一个数  2 或者 4
                    new_grid = create_new_value(new_grid_buffer)        #新生成 2/4
                    draw_grid(new_grid)     #重新绘制界面
        else:
            print(event)        #打印所有事件
    # 绘制背景,背景颜色是白色
    pygame.draw.rect(screen,(255,255,255),(0,0,w,h))

    #刷新表格外观
    draw_grid(new_grid)

    #设置时钟频率
    fclock.tick(fps)
    # 刷新画面
    pygame.display.update()

Python3 正则表达式

正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。

re 模块使 Python 语言拥有全部的正则表达式功能。

compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换。

re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数。

本章节主要介绍 Python 中常用的正则表达式处理函数,如果你对正则表达式不了解,可以查看我们的 正则表达式 - 教程。

re.match函数
re.match 尝试从字符串的起始位置匹配一个模式,如果不是起始位置匹配成功的话,match()就返回none。

函数语法:

re.match(pattern, string, flags=0)

函数参数说明:
pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

匹配成功re.match方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法 , 描述
group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
实例

#!/usr/bin/python
 
import re
print(re.match('www', 'www.runoob.com').span())  # 在起始位置匹配
print(re.match('com', 'www.runoob.com'))         # 不在起始位置匹配
以上实例运行输出结果为:

(0, 3)
None
实例
#!/usr/bin/python3
import re
 
line = "Cats are smarter than dogs"
# .* 表示任意匹配除换行符(\n、\r)之外的任何单个或多个字符
matchObj = re.match( r'(.*) are (.*?) .*', line, re.M|re.I)
 
if matchObj:
   print ("matchObj.group() : ", matchObj.group())
   print ("matchObj.group(1) : ", matchObj.group(1))
   print ("matchObj.group(2) : ", matchObj.group(2))
else:
   print ("No match!!")

以上实例执行结果如下:

matchObj.group() :  Cats are smarter than dogs
matchObj.group(1) :  Cats
matchObj.group(2) :  smarter

re.search方法
re.search 扫描整个字符串并返回第一个成功的匹配。

函数语法:

re.search(pattern, string, flags=0)

函数参数说明:

参数 描述

pattern 匹配的正则表达式
string 要匹配的字符串。
flags 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。

匹配成功re.search方法返回一个匹配的对象,否则返回None。
我们可以使用group(num) 或 groups() 匹配对象函数来获取匹配表达式。

匹配对象方法 描述

group(num=0) 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组。
groups()返回一个包含所有小组字符串的元组,从 1 到 所含的小组号。
实例

#!/usr/bin/python3
 
import re
 
print(re.search('www', 'www.runoob.com').span())  # 在起始位置匹配
print(re.search('com', 'www.runoob.com').span())         # 不在起始位置匹配

以上实例运行输出结果为:

(0, 3)
(11, 14)

实例

#!/usr/bin/python3
 
import re
 
line = "Cats are smarter than dogs";
 
searchObj = re.search( r'(.*) are (.*?) .*', line, re.M|re.I)
 
if searchObj:
   print ("searchObj.group() : ", searchObj.group())
   print ("searchObj.group(1) : ", searchObj.group(1))
   print ("searchObj.group(2) : ", searchObj.group(2))
else:
   print ("Nothing found!!")

以上实例执行结果如下:

searchObj.group() :  Cats are smarter than dogs
searchObj.group(1) :  Cats
searchObj.group(2) :  smarter

re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。

实例

#!/usr/bin/python3
 
import re
 
line = "Cats are smarter than dogs";
 
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
   print ("match --> matchObj.group() : ", matchObj.group())
else:
   print ("No match!!")
 
matchObj = re.search( r'dogs', line, re.M|re.I)
if matchObj:
   print ("search --> matchObj.group() : ", matchObj.group())
else:
   print ("No match!!")

以上实例运行结果如下:

No match!!
search --> matchObj.group() :  dogs

检索和替换
Python 的re模块提供了re.sub用于替换字符串中的匹配项。

语法:

re.sub(pattern, repl, string, count=0, flags=0)

参数:

pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
flags : 编译时用的匹配模式,数字形式。
前三个为必选参数,后两个为可选参数。

实例

#!/usr/bin/python3
import re
 
phone = "2004-959-559 # 这是一个电话号码"
 
# 删除注释
num = re.sub(r'#.*$', "", phone)
print ("电话号码 : ", num)
 
# 移除非数字的内容
num = re.sub(r'\D', "", phone)
print ("电话号码 : ", num)

以上实例执行结果如下:

电话号码 :  2004-959-559 
电话号码 :  2004959559

repl 参数是一个函数
以下实例中将字符串中的匹配的数字乘于 2:

实例

#!/usr/bin/python
 
import re
 
# 将匹配的数字乘于 2
def double(matched):
    value = int(matched.group('value'))
    return str(value * 2)
 
s = 'A23G4HFD567'
print(re.sub('(?P<value>\d+)', double, s))

执行输出结果为:

A46G8HFD1134

compile 函数
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match() 和 search() 这两个函数使用。

语法格式为:

re.compile(pattern[, flags])

参数:

pattern : 一个字符串形式的正则表达式
flags: 可选,表示匹配模式,比如忽略大小写,多行模式等,具体参数为:
re.I 忽略大小写

  • re.L 表示特殊字符集 \w, \W, \b, \B, \s, \S 依赖于当前环境
    re.M 多行模式
    re.S 即为’ . ‘并且包括换行符在内的任意字符(’ . ‘不包括换行符)
    re.U 表示特殊字符集 \w, \W, \b, \B, \d, \D, \s, \S 依赖于 Unicode 字符属性数据库
    re.X 为了增加可读性,忽略空格和’ # '后面的注释

实例

>>>import re
>>> pattern = re.compile(r'\d+')                    # 用于匹配至少一个数字
>>> m = pattern.match('one12twothree34four')        # 查找头部,没有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 2, 10) # 从'e'的位置开始匹配,没有匹配
>>> print m
None
>>> m = pattern.match('one12twothree34four', 3, 10) # 从'1'的位置开始匹配,正好匹配
>>> print m                                         # 返回一个 Match 对象
<_sre.SRE_Match object at 0x10a42aac0>
>>> m.group(0)   # 可省略 0
'12'
>>> m.start(0)   # 可省略 0
3
>>> m.end(0)     # 可省略 0
5
>>> m.span(0)    # 可省略 0
(3, 5)

在上面,当匹配成功时返回一个 Match 对象,其中:

group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
span([group]) 方法返回 (start(group), end(group))。
再看看一个例子:

实例

>>>import re
>>> pattern = re.compile(r'([a-z]+) ([a-z]+)', re.I)   # re.I 表示忽略大小写
>>> m = pattern.match('Hello World Wide Web')
>>> print m                               # 匹配成功,返回一个 Match 对象
<_sre.SRE_Match object at 0x10bea83e8>
>>> m.group(0)                            # 返回匹配成功的整个子串
'Hello World'
>>> m.span(0)                             # 返回匹配成功的整个子串的索引
(0, 11)
>>> m.group(1)                            # 返回第一个分组匹配成功的子串
'Hello'
>>> m.span(1)                             # 返回第一个分组匹配成功的子串的索引
(0, 5)
>>> m.group(2)                            # 返回第二个分组匹配成功的子串
'World'
>>> m.span(2)                             # 返回第二个分组匹配成功的子串索引
(6, 11)
>>> m.groups()                            # 等价于 (m.group(1), m.group(2), ...)
('Hello', 'World')
>>> m.group(3)                            # 不存在第三个分组
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
IndexError: no such group

findall 函数
在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。

注意: match 和 search 是匹配一次 findall 匹配所有。

语法格式为:

re.findall(string[, pos[, endpos]])

参数:

string 待匹配的字符串。
pos 可选参数,指定字符串的起始位置,默认为 0。
endpos 可选参数,指定字符串的结束位置,默认为字符串的长度。
查找字符串中的所有数字:

实例

import re
 
pattern = re.compile(r'\d+')   # 查找数字
result1 = pattern.findall('runoob 123 google 456')
result2 = pattern.findall('run88oob123google456', 0, 10)
 
print(result1)
print(result2)

输出结果:

['123', '456']
['88', '12']

re.finditer 函数

re.finditer和 findall 类似,在字符串中找到正则表达式所匹配的所有子串,并把它们作为一个迭代器返回。

re.finditer(pattern, string, flags=0)

参数:

参数 描述
pattern 匹配的正则表达式
string要匹配的字符串。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
实例

import re
 
it = re.finditer(r"\d+","12a32bc43jf3") 
for match in it: 
    print (match.group() )

输出结果:

12 
32 
43 
3

re.split
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:

re.split(pattern, string[, maxsplit=0, flags=0])

参数:

参数 描述

pattern 匹配的正则表达式
string要匹配的字符串。
maxsplit分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。
flags标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
实例

>>>import re
>>> re.split('\W+', 'runoob, runoob, runoob.')
['runoob', 'runoob', 'runoob', '']
>>> re.split('(\W+)', ' runoob, runoob, runoob.') 
['', ' ', 'runoob', ', ', 'runoob', ', ', 'runoob', '.', '']
>>> re.split('\W+', ' runoob, runoob, runoob.', 1) 
['', 'runoob, runoob, runoob.']
 
>>> re.split('a*', 'hello world')   # 对于一个找不到匹配的字符串而言,split 不会对其作出分割
['hello world']

正则表达式对象

re.RegexObject

re.compile() 返回 RegexObject 对象。

re.MatchObject

group() 返回被 RE 匹配的字符串。
start() 返回匹配开始的位置
end() 返回匹配结束的位置
span() 返回一个元组包含匹配 (开始,结束) 的位置

正则表达式修饰符 - 可选标志

正则表达式可以包含一些可选标志修饰符来控制匹配的模式。修饰符被指定为一个可选的标志。多个标志可以通过按位 OR(|) 它们来指定。如 re.I | re.M 被设置成 I 和 M 标志:
在这里插入图片描述
正则表达式模式

模式字符串使用特殊的语法来表示一个正则表达式:
字母和数字表示他们自身。一个正则表达式模式中的字母和数字匹配同样的字符串。
多数字母和数字前加一个反斜杠时会拥有不同的含义。
标点符号只有被转义时才匹配自身,否则它们表示特殊的含义。
反斜杠本身需要使用反斜杠转义。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'\t',等价于 \\t )匹配相应的特殊字符。

下表列出了正则表达式模式语法中的特殊元素。如果你使用模式的同时提供了可选的标志参数,某些模式元素的含义会改变。
在这里插入图片描述

正则表达式实例:
在这里插入图片描述

常用正则表达式

一、校验数字的表达式

数字:^[0-9]*$
n位的数字:^\d{n}$
至少n位的数字:^\d{n,}$
m-n位的数字:^\d{m,n}$
零和非零开头的数字:^(0|[1-9][0-9]*)$
非零开头的最多带两位小数的数字:^([1-9][0-9]*)+(\.[0-9]{1,2})?$
带1-2位小数的正数或负数:^(\-)?\d+(\.\d{1,2})$
正数、负数、和小数:^(\-|\+)?\d+(\.\d+)?$
有两位小数的正实数:^[0-9]+(\.[0-9]{2})?$
有1~3位小数的正实数:^[0-9]+(\.[0-9]{1,3})?$
非零的正整数:^[1-9]\d*$ 或 ^([1-9][0-9]*){1,3}$ 或 ^\+?[1-9][0-9]*$
非零的负整数:^\-[1-9][]0-9"*$ 或 ^-[1-9]\d*$
非负整数:^\d+$ 或 ^[1-9]\d*|0$
非正整数:^-[1-9]\d*|0$ 或 ^((-\d+)|(0+))$
非负浮点数:^\d+(\.\d+)?$ 或 ^[1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0$
非正浮点数:^((-\d+(\.\d+)?)|(0+(\.0+)?))$ 或 ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
正浮点数:^[1-9]\d*\.\d*|0\.\d*[1-9]\d*$ 或 ^(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*))$
负浮点数:^-([1-9]\d*\.\d*|0\.\d*[1-9]\d*)$ 或 ^(-(([0-9]+\.[0-9]*[1-9][0-9]*)|([0-9]*[1-9][0-9]*\.[0-9]+)|([0-9]*[1-9][0-9]*)))$
浮点数:^(-?\d+)(\.\d+)?$ 或 ^-?([1-9]\d*\.\d*|0\.\d*[1-9]\d*|0?\.0+|0)$

二、校验字符的表达式

汉字:^[\u4e00-\u9fa5]{0,}$
英文和数字:^[A-Za-z0-9]+$ 或 ^[A-Za-z0-9]{4,40}$
长度为3-20的所有字符:^.{3,20}$
由26个英文字母组成的字符串:^[A-Za-z]+$
由26个大写英文字母组成的字符串:^[A-Z]+$
由26个小写英文字母组成的字符串:^[a-z]+$
由数字和26个英文字母组成的字符串:^[A-Za-z0-9]+$
由数字、26个英文字母或者下划线组成的字符串:^\w+$ 或 ^\w{3,20}$
中文、英文、数字包括下划线:^[\u4E00-\u9FA5A-Za-z0-9_]+$
中文、英文、数字但不包括下划线等符号:^[\u4E00-\u9FA5A-Za-z0-9]+$^[\u4E00-\u9FA5A-Za-z0-9]{2,20}$
可以输入含有^%&’,;=?KaTeX parse error: Can't use function '\"' in math mode at position 1: \̲"̲等字符:`[^%&',;=?\x22]+禁止输入含有~的字符:[^~\x22]+`

三、特殊需求表达式

Email地址:^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$
域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(/.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+/.?
InternetURL:[a-zA-z]+://[^\s]*^http://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?$
手机号码:^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$
电话号码(“XXX-XXXXXXX”、“XXXX-XXXXXXXX”、“XXX-XXXXXXX”、“XXX-XXXXXXXX”、"XXXXXXX"和"XXXXXXXX):^(\(\d{3,4}-)|\d{3.4}-)?\d{7,8}$
国内电话号码(0511-4405222、021-87888822):\d{3}-\d{8}|\d{4}-\d{7}
电话号码正则表达式(支持手机号码,3-4位区号,7-8位直播号码,1-4位分机号): ((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)
身份证号(15位、18位数字),最后一位是校验位,可能为数字或字符X:(^\d{15}$)|(^\d{18}$)|(^\d{17}(\d|X|x)$)
帐号是否合法(字母开头,允许5-16字节,允许字母数字下划线):^[a-zA-Z][a-zA-Z0-9_]{4,15}$
密码(以字母开头,长度在6~18之间,只能包含字母、数字和下划线):^[a-zA-Z]\w{5,17}$
强密码(必须包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间):^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,10}$
日期格式:^\d{4}-\d{1,2}-\d{1,2}
一年的12个月(01~09和1~12):^(0?[1-9]|1[0-2])$
一个月的31天(01~09和1~31):^((0?[1-9])|((1|2)[0-9])|30|31)$
钱的输入格式:
有四种钱的表示形式我们可以接受:“10000.00” 和 “10,000.00”, 和没有 “分” 的 “10000” 和 “10,000”:^[1-9][0-9]*$
这表示任意一个不以0开头的数字,但是,这也意味着一个字符"0"不通过,所以我们采用下面的形式:^(0|[1-9][0-9]*)$
一个0或者一个不以0开头的数字.我们还可以允许开头有一个负号:^(0|-?[1-9][0-9]*)$
这表示一个0或者一个可能为负的开头不为0的数字.让用户以0开头好了.把负号的也去掉,因为钱总不能是负的吧。下面我们要加的是说明可能的小数部分:^[0-9]+(.[0-9]+)?$
必须说明的是,小数点后面至少应该有1位数,所以"10.“是不通过的,但是 “10” 和 “10.2” 是通过的:^[0-9]+(.[0-9]{2})?$
这样我们规定小数点后面必须有两位,如果你认为太苛刻了,可以这样:^[0-9]+(.[0-9]{1,2})?$
这样就允许用户只写一位小数.下面我们该考虑数字中的逗号了,我们可以这样:^[0-9]{1,3}(,[0-9]{3})*(.[0-9]{1,2})?$
1到3个数字,后面跟着任意个 逗号+3个数字,逗号成为可选,而不是必须:^([0-9]+|[0-9]{1,3}(,[0-9]{3})*)(.[0-9]{1,2})?$
备注:这就是最终结果了,别忘了”+“可以用”*"替代如果你觉得空字符串也可以接受的话(奇怪,为什么?)最后,别忘了在用函数时去掉去掉那个反斜杠,一般的错误都在这里
xml文件:^([a-zA-Z]+-?)+[a-zA-Z0-9]+\\.[x|X][m|M][l|L]$
中文字符的正则表达式:[\u4e00-\u9fa5]
双字节字符:[^\x00-\xff] (包括汉字在内,可以用来计算字符串的长度(一个双字节字符长度计2,ASCII字符计1))
空白行的正则表达式:\n\s*\r (可以用来删除空白行)
HTML标记的正则表达式:<(\S*?)[^>]*>.*?|<.*? /> ( 首尾空白字符的正则表达式:^\s*|\s*$或(^\s*)|(\s*$) (可以用来删除行首行尾的空白字符(包括空格、制表符、换页符等等),非常有用的表达式)
腾讯QQ号:[1-9][0-9]{4,} (腾讯QQ号从10000开始)
中国邮政编码:[1-9]\d{5}(?!\d) (中国邮政编码为6位数字)
IP地址:((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))

©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页