Python基础入门 - 正则表达式与综合实战

1. 初识正则表达式

1.1 介绍

  1. 步骤介绍
    正则表达式入门及应用
    正则表达式的进阶
    正则表达式案例

1.2 正则表达式基本操作

  1. 什么是正则表达式
    正则表达式(regex)是一些由字符和特殊符号组成的字符串。
    正则表达式是能按照某种模式匹配一系列有相似特征的字符串。
  2. 正则表达式中的符号
符号 描述 示例
literal 匹配文本字符串的字面值literal foo
re1|re2 匹配正则表达式re1或者re2 foo|bar
. 匹配任何字符(除了\n之外) b.b
^ 匹配字符串起始部分 ^Dear
$ 匹配字符串终止部分 /bin/*sh$
* 匹配0次或多次前面出现的正则表达式 [A-Za-z0-9]*
+ 匹配1次或多次前面出现的正则表达式 [a-z]+\.com
? 匹配0次或1次前面出现的正则表达式,或指明非贪婪限模式匹配。 goo?
{N} 匹配N次前面出现的正则表达式 [0-9]{3}
{M, N} 匹配M-N次前面出现的正则表达式 [0-9]{5,9}
[...] 匹配来自字符集的任意单一字符 [aeiou]
[x-y] 匹配x~y范围中的任意单一字符 [0-9],[A-Za-z]
[^...] 不匹配此字符集中出现的任何一个字符,包括某一范围的字符(如果此字符集中出现) [^aeiou],[^A-Za-z0-9]
(...) 匹配封闭的正则表达式,然后另存为子组 ([0-9]{3}?,f(oo|u)bar

贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配字符。
非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配字符。
注释:默认是贪婪模式。

  1. 正则表达式中的特殊字符
    \d - 匹配一个数字字符。等价于[0-9]
    \D - 匹配一个非数字字符。等价于[^0-9]
    \w - 匹配包括下划线的任何单词字符。等价于[A-Za-z0-9_]
    \W - 匹配任何非单词字符。等价于[^A-Za-z0-9_]
    \s - 匹配任何不可见字符,包括空格、制表符、换页符等
    \S - 匹配任何可见字符
    \b - 匹配一个单词的边界
    \B - 匹配非单词边界
    \n - 匹配一个换行符
  2. 修饰符
    re.I-使匹配对大小写不敏感
    re.L-做本地化识别(locale-aware)匹配
    re.M-多行匹配,影响 ^$
    re.S-使.匹配包括换行在内的所有字符

1.3 正则表达式应用

  1. 身份证号码匹配
    区域编号、出生年份、出生日期、性别(倒数第二位)
    (\d{6})(\d{4})((\d{2})(\d{2}))\d{2}\d([0-9]|X)
  2. 电子邮箱表达式匹配
    [a-zA-Z0-9_-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*(\.[a-zA-Z]{2,5})
  3. 贪婪模式与非贪婪模式
import re

content = "abcabca"
regex1 = re.compile('ab.*a')
regex2 = re.compile('ab.*?a')
print(regex1.match(content).group())  # abcabca
print(regex2.match(content).group())  # abca

1.4 正则表达式进阶

  1. 使用re模块直接匹配
import re

print(re.match('hello', 'hello world'))  # <re.Match object; span=(0, 5), match='hello'>
  1. 先编译再匹配
import re

# 将正则表达式编译
pattern = re.compile('hello')

# 通过match进行匹配
result = pattern.match('hello world')
print(result)  # <re.Match object; span=(0, 5), match='hello'>

注释:先编译再匹配的方式性能较高。

  1. 匹配不到则返回None
import re

pattern = re.compile('hello')
print(pattern.match('Hello'))  # None
  1. 忽略大小写
import re

pattern = re.compile('hello', re.I)
print(pattern.match('Hello'))  # <re.Match object; span=(0, 5), match='Hello'>
  1. r转义
    使用Pythonr前缀,就不用考虑转义的问题了。
import re

pattern1 = re.compile('A\\b')
pattern2 = re.compile(r'A\b')

print(pattern1.match('A\b'))
# <re.Match object; span=(0, 1), match='A'>
print(pattern1.match('A\b'))
# <re.Match object; span=(0, 1), match='A'>

注释:pattern1pattern2写法等价。

  1. findall方法
import re

content = 'a1B22ccc333D4'

p2 = re.compile(r'[a-z]+', re.I)
print(p2.findall(content))  # ['a', 'B', 'ccc', 'D']

print(re.findall(r'[a-z]+', content, re.I))  # ['a', 'B', 'ccc', 'D']
print(re.findall(r'([a-z])\d', content, re.I))  # ['a', 'B', 'c', 'D']
print(re.findall(r'([a-z]+)(\d)', content, re.I))  # [('a', '1'), ('B', '2'), ('ccc', '3'), ('D', '4')]

注释:groupfindall结合使用时,findall可以匹配组内字符串。

  1. search方法
import re

content = 'hello world!'

regex = re.compile(r'world')
print(regex.search(content))
# <re.Match object; span=(6, 11), match='world'>

print(re.search(r'world', content))
# <re.Match object; span=(6, 11), match='world'>
  1. match()search()的区别
    match()函数只检测字符串开头位置是否匹配,匹配成功返回结果。用于判断字符串开头或整个字符串是否匹配,速度快。
    search()会整个字符串查找,直到找到一个匹配。
import re

content = 'hello world!'

print(re.search(r'hello', content))
# <re.Match object; span=(0, 5), match='hello'>
print(re.search(r'world', content))
# <re.Match object; span=(6, 11), match='world'>

print(re.match(r'hello', content))
# <re.Match object; span=(0, 5), match='hello'>
print(re.match(r'world', content))
# None
  1. group()groups()的使用
import re

result = re.search(r'world', 'hello world!')
print(result)
# <re.Match object; span=(6, 11), match='world'>
print(result.group())  # world
print(result.groups())  # ()

identity = '411423202010060028'
regex = re.compile(r'(\d{6})(?P<year>\d{4})((?P<month>\d{2})(?P<day>\d{2}))\d{2}\d(?P<sex>[0-9]|X)')
result = regex.search(identity)
print(result.group())  # 411423202010060028
print(result.group(2))  # 2020
print(result.groups())  # ('411423', '2020', '1006', '10', '06', '8')
print(result.groupdict())
# {'year': '2020', 'month': '10', 'day': '06', 'sex': '8'}

注释:(?P<name>regex)表示给组regex命名为name

  1. split()正则切割
import re

s = 'one1two22three333four4five5six6'

print(re.split(r'\d+', s))
# ['one', 'two', 'three', 'four', 'five', 'six', '']
  1. sub()正则替换
import re

# 字符替换
s = 'one1two22three333four4five5six6'
s1 = re.sub(r'\d+', '@', s)
print(s1)
# one@two@three@four@five@six@

# 分组替换
s2 = 'hello world'
s3 = re.sub(r'(\w+) (\w+)', r'\2 \1', s2)
print(s3)  # world hello


# 复杂替换
s3 = 'hello world'
s4 = re.sub(r'(\w+) (\w+)', lambda m: m.group(2).upper() + ' ' + m.group(1).upper(), s2)
print(s4)  # WORLD HELLO

1.5 正则表达式综合实战

  1. 匹配html字符串中的图片src
import re

with open('src.html', encoding='utf-8') as f:
    html = f.read()
    regex = re.compile(r'<img.+?src="(.+?)".+?>')
    images = regex.findall(html)
    for ls in images:
        print(ls)

注释:?实现非贪婪匹配。findall获取group内字符串。

2. 综合实战 - 飞机大战

2.1 介绍

  1. 目标
    掌握面向对象分析和开发的思想
    能对项目进行拆分,进行模块化开发
    了解项目开发的基本流程
    理解并运用Python包、模块相关知识
    理解并运用文件读写函数式编程
    理解简单2d游戏开发的基本思路
    掌握IDE调试技巧
  2. 重难点技能
    面向对象分析及开发方法
    Python包与模块:标准模块和第三方模块的使用
    Python多线程、多进程的运用
    游戏开发入门及对Pygame的使用

2.2 Pygame介绍及使用

  1. Pygame介绍
    2D游戏开发工具包。
  2. Pygame文档
    http://www.pygame.org/docs/
  3. Pygame安装
    (1) 创建项目
    image.png

    (2) 安装pygame
(PlaneWars) ➜  PlaneWars pip install pygame
Collecting pygame
  Downloading https://files.pythonhosted.org/packages/32/37/453bbb62f90feff2a2b75fc739b674319f5f6a8789d5d21c6d2d7d42face/pygame-1.9.6-cp37-cp37m-macosx_10_11_intel.whl (4.9MB)
    100% |████████████████████████████████| 4.9MB 1.5MB/s 
Installing collected packages: pygame
Successfully installed pygame-1.9.6
(PlaneWars) ➜  PlaneWars python
  1. pygame示例
import sys, pygame

# 1. pygame初始化
pygame.init()

size = width, height = 320, 240  # 元组,等价于(320, 240)
speed = [2, 2]
black = 0, 0, 0  # 元组,等价于(0, 0, 0)

# 2. 创建窗口对象
screen = pygame.display.set_mode(size)
# 获取图片对象
ball = pygame.image.load("intro_ball.gif")
# 获取图片对象位置
ballrect = ball.get_rect()

# 3. 游戏主循环
while 1:
    # 处理游戏事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()

    # 更新游戏状态(图片对象位置)
    ballrect = ballrect.move(speed)
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]
    
    # 窗口视图绘制
    screen.fill(black)  # 使用黑色填充窗口
    screen.blit(ball, ballrect)  # 指定位置绘制图片
    pygame.display.flip() # 更新窗口
  1. 游戏中的图片
    (1) 图片加载
    bg = pygame.image.load(url)
    (2) 获取图片尺寸
    rect = bg.get_rect()
    (3) 图片移动
    rect.move((x, y))
    (4) 图片绘制
    screen.blit(ball, (x, y)/rect)
import sys, pygame

# 初始化
pygame.init()

# 屏幕对象
screen = pygame.display.set_mode((500, 500))
# 加载图片
ball = pygame.image.load('intro_ball.gif')
# 获取图片位置
rect = ball.get_rect()

while True:
    # 处理事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    # 绘制
    screen.blit(ball, rect)
    screen.blit(ball, rect.move([50, 50]))
    screen.blit(ball, (100, 100))
    pygame.display.flip()

注释:pygame.display.set_mode()pygame.image.load()方法返回值都是Surface对象。Surface.get_size()方法可以获取尺寸。

  1. Surface对象与Rect对象
    (1) Surface对象
    pygame.Surface.get_size
    pygame.Surface.get_width
    pygame.Surface.get_height
    pygame.Surface.get_rect
    (2) Rect对象
    pygame.Rect.move
    Rect对象具有几个虚拟属性,可用于移动和对齐Rect
    x,y,top, left, bottom, right,topleft, bottomleft, topright, bottomright,midtop, midleft, midbottom, midright,center, centerx, centery,size, width, height,w,h
    其中,尺寸初始信息为图片原始尺寸大小,位置初始信息为(0, 0)
  2. 游戏中的颜色和形状
import sys, pygame

# 初始化
pygame.init()

# 屏幕对象
screen = pygame.display.set_mode((500, 500))

red = pygame.Color(255, 0, 0)

while True:
    # 处理事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    # 直线
    pygame.draw.line(screen, red, (10, 10), (80, 80), 5)
    # 矩形
    pygame.draw.rect(screen, red, (100, 100, 50, 50), 1)
    # 圆
    pygame.draw.circle(screen, red, (300, 300), 50, 10)
    pygame.display.flip()
  1. 游戏中的文字
import sys, pygame


pygame.init()

screen = pygame.display.set_mode((500, 500))
red = pygame.Color(255, 0, 0)

font = pygame.font.Font('./static/hwxw.ttf', 60) # 字体文件 字体大小
text = font.render('华文新魏', True, red, (255, 255, 255)) # 文字 平滑字体 文字颜色 背景颜色

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

    screen.blit(text, (20, 100))
    pygame.display.flip()

注释:颜色可以用pygame.Color(R, G, B)生成,也可以用(R, G, B)元组表示。

  1. 游戏中的音乐
import sys, pygame

pygame.init()

screen = pygame.display.set_mode((500, 500))

pygame.mixer.music.load('./static/bg_music.mp3')  # 加载音乐
pygame.mixer.music.set_volume(0.5)  # 设置音量(0-1)
pygame.mixer.music.play(-1)  # 循环播放

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

注释:game.mixer.music用来播放背景音乐。

  1. 游戏中的音效
import pygame

pygame.init()
sound = pygame.mixer.Sound('./static/bullet.wav')
sound.play()

while True:
    pass

注释:pygame.mixer.Sound()播放音效。音频可以可以是OGG音频文件或者WAV音频文件

  1. 游戏中的动画切换
import sys, pygame

pygame.init()

screen = pygame.display.set_mode((500, 500))

hero1 = pygame.image.load('./static/hero1.png')
hero2 = pygame.image.load('./static/hero2.png')
clock = pygame.time.Clock()

count = 1
while True:
    clock.tick(60)  # 设置动画帧数
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
    screen.fill((255, 255, 255))
    # 等价写法: screen.fill(pygame.Color(255, 255, 255))
    if count % 2 == 0:
        screen.blit(hero1, (100, 100))
    else:
        screen.blit(hero2, (100, 100))
    count += 1
    pygame.display.flip()
  1. 精灵、精灵组与碰撞检测
    (1) 两个精灵之间的矩形检测
    pygame.sprite.collide_rect
    pygame.sprite.collide_rect_ratio
    (2) 两个精灵之间的圆形检测
    pygame.sprite.collide_circle
    pygame.sprite.collide_circle_ratio
    (3) 两个精灵之间的像素遮罩检测
    pygame.sprite.collide_mask
    (4) 精灵与精灵组之间的碰撞检测
    pygame.sprite.spritecollide
    (5) 两个精灵组之间的碰撞检测
    pygame.sprite.groupcollide
    (6) 将精灵从所有精灵组中删除
    pygame.sprite.Sprite.kill
    (7) 删除所有精灵
    pygame.sprite.Group.empty
import sys, pygame

# 初始化
pygame.init()

# 屏幕对象
screen = pygame.display.set_mode((500, 500))


class Block(pygame.sprite.Sprite):
    def __init__(self, color, x, y, width, height):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface([width, height])
        self.image.fill(color)
        self.rect = pygame.Rect(x, y, width, height)

    def move(self, x, y):
        self.rect = self.rect.move(x, y)


s1 = Block((255, 0, 0), 50, 50, 50, 50)
s2 = Block((0, 255, 0), 90, 90, 100, 50)

while True:
    # 处理事件
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    screen.blit(s1.image, s1.rect)
    screen.blit(s2.image, s2.rect)
    # 矩形检测碰撞
    result1 = pygame.sprite.collide_rect(s1, s2)
    # 使用缩放为一定比例的圆,检测两个小精灵之间的碰撞
    result2 = pygame.sprite.collide_circle_ratio(0.5)(s1, s2)
    print(result1, result2)  # 1 False
    pygame.display.flip()

2.3 实战:飞机大战游戏

  1. 开发步骤
    面向对象项目分析
    项目初始化
    载入我方飞机
    载入敌方飞机
    碰撞检测、爆炸效果及音效
    成绩统计
  2. 项目扩展完善
    使用多线程/多进程来扩展敌机数量
    爆炸效果延时展示
    添加游戏暂停功能
    添加中型敌机,大型敌机
    添加多条生命
    记录玩家的多条分数记录
    敌机发射子弹
  3. 代码地址
    https://github.com/nmwei/PlaneWars
    https://github.com/nmwei/MyPlaneWars
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容