• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

Python文件处理、异常处理、finally、with、装饰器、可迭代器、正则表达式

开发技术 开发技术 3小时前 1次浏览

文件处理

文件操作:
#打开文件
#python 里使用 open 内置函数打开并操作一个文件

# open 参数介绍
# file :用来指定打开的文件(不是文件的名字,而是文件的路径)
# mode :打开文件时的模式,默认是r只读,默认使用rt(只读文本模式打开)
# encoding :打开文件时的编码方式
#def open(file, mode='r', buffering=None,
    # encoding=None, errors=None,
    # newline=None, closefd=True):
    # known special case of open

#open 函数会有一个返回值,打开的文件对象
file1 = open('D:\文档\VScode-Python\Study\快捷键',encoding='utf8')
#注意'快捷键.txt'写入时,使用的是utf8编码格式,但是在Windows系统里,默认使用gbk编码格式打开文件
#下面可能会报错,解决方案:写入和读取使用相同的编码格式
print(type(file1))
print(file1.read())
file1.close()#操作完成文件以后,关闭文件


# 文件的路径
# file : 用来指定打开的文件路径
import os
print(os.name)  # NT/posix
print(os.sep)  # windows系统里,文件夹之间使用分隔。
# 在Python字符串里,表示转义字符
# 路径分为两种:
# 1、绝对路径:从电脑盘符开始的路径
# 需要这样写:file = open('D:\文档\VScode-Python\Study\快捷键',encoding='utf8')
# 当然还有其他方法 :file = open('D:\文档\VScode-Python\Study\快捷键',encoding='utf8')
#在非Windows系统里,文件夹之间使用 / 分隔
# file = open('D:/文档/VScode-Python/Study/快捷键',encoding='utf8')推荐使用
# 所以有三种方式:'\'  r''  '/'

# 2、相对路径:当前文件所在的文件夹开始的路径,开发时多用相对路径,绝对路径会出问题
# ../ 表示返回到上一级文件夹
# ./ 可以省略不写,表示当前文件夹
# 切记 / 不能随便用(特别是Linux系统)
file = open('../快捷键',encoding='utf8')
print(type(file))
print(file.read())
file.close()


#文件的打开方式

mode 指的是文件的打开方式
file = open('wenjain','r')
r :只读模式,默认打开文件以后只能读取,不能写入,否则会报错,同时如果文件不存在会报notfound
    使用file.read()读取文件内容
w :写入模式,打开文件以后,只能写入,不能读取。如果文件存在,会覆盖文件;如果文件不存在则会创建文件,
    使用file.write('neirong')来写入文件
b :以二进制的形式打开文件,rb:以二进制读取文件;wb:以二进制写入文件(可以用来操作非文本文件)
file.write('你好') #报错TypeError: a bytes-like object is required,not 'str',只能写入二进制
我们需要指定编码格式:file.write('你好',encoding('utf8'))
file.close()
具体解释如下:
file.seek(0.0)调用seek将文件指针重置到开头
a:追加模式,会在最后追加内容,如果文件不存在,会创建文件;如果文件存在,文件指针就会放在文件的结尾,就会追加
r+打开一个文件用于读写.文件指针将会放在文件的开头,如果文件不存在会报错
w+打开一个文件用于读写.如果该文件已存在则将其覆盖.如果该文件不存在,创建新文件
a+打开一个文件用于读写.如果该文件已存在,文件指针将会放在文件的结尾.文件打开时会是追加模式.如果该文件不存在,创建新文件用于读写.
rb以二进制格式打开一个文件用于只读.文件指针将会放在文件的开头
wb以二进制格式打开一个文件只用于写入.如果该文件已存在则将其覆盖.如果该文件不存在,创建新文件
ab以二进制格式打开一个文件用于追加.如果该文件已存在,文件指针将会放在文件的结尾.也就是说,新的内容将会被写入到已有内容之后.如果该文件不存在,创建新文件进行写入
rb+以二进制格式打开一个文件用于读写,文件指针将会放在文件的开头
wb+以二进制格式打开个文件用于读写,如果该文件已存在则将其搜盖,如果该文件不存在,创建新文件
ab+以二进制格式打开一个文件用于读写.如果该文件已存在,文件指针将会放在文件的结尾.如果亥文件不存在,创建新文件用于读写
# 读取文件
file = open('../快捷键',encoding='utf8')
print(file.read())
print(file.readline())#只读取一行数据
while True:
    content=file.readline()
    print(content)
    if  content=='':
        break
x=file.readlines()#读取所有行的数据,保存到一个列表里
print(x)
y=file.read(2)#指的是读取的长度
print(y)
file.close()
实现文件拷贝功能
import os
file_name  = input('请输入一个文件的路径:')
if os.path.isfile(file_name):
    #打开旧文件
    old_file=open(file_name,encoding='utf8')
    names= file_name.rpartition('.')
    new_file_name= names[0]+'.bak.'+names[-1]
    #还可以使用os模块里的方法:
        # names = os.path.splitext(file_name)
    new_file=open(new_file_name,'w',encoding='utf8')#打开一个新文件用于写入
    #把旧文件的数据读取出来写入到新的文件
    new_file.write(old_file.read())
    new_file.close()
    old_file.close()
else:
    print('您输入的文件不存在')


但是上面的代码还可以优化减少bug,如下:
import os
file_name  = input('请输入一个文件的路径:')
if os.path.isfile(file_name):
    old_file=open(file_name,'rb')#以二进制的形式读取文件
    names= file_name.rpartition('.')
    new_file_name= names[0]+'.bak.'+names[-1]
    #还可以使用os模块里的方法:
        # names = os.path.splitext(file_name)
        # new_file_name[0]+'.bak'+names[1]
    new_file=open(new_file_name,'wb')#以二进制的形式写入文件
    #注意下面这段还有改进的地方:
    # content=old_file.read()#读取出来的内容是二进制的
    while True:
        content=old_file.read(1024)
        new_file.write(content)
        if not content:
            break
    new_file.close()
    old_file.close()
else:
    print('您输入的文件不存在')

CSV文件
CSV文件:Comma-Separated Values,中文叫逗号分隔值或者字符分割值,其文件以纯文本的形式存储表格数据.可以把它理解为一个表格,只不过这个表格是以纯文本的形式显示的,单元格与单元格之间,默认使用逗号进行分隔;每行数据之间,使用换行进行分隔
eg:
	name,age,score
	zhangsan,18,98
	lisi,20,99
	wangwu,17,90
	jerry,19,95
Python中CSV模块,提供了相应的函数,可以让我们很方便的读写CSV文件

对于下面的讨论,我们提前新建info.csv和demo1.csv
    name,age,aex,city
    zhangsan,18,mela,shanghai
    lisi,20,mela,beijing
    wangwu,17,femela,nanjing
    jerry,19,femela,wuhan
    tom,22,mela,shenzhen
    
    name,age,score,city
    zhangsan,18,98,shanghai
    lisi,20,99,beijing
    wangwu,17,90,nanjing
    jerry,19,95,hefei


1、CSV文件的写入
import csv #系统内置模块
# 以写入方式打开一个CSV文件
file = open('demo1.csv','w',encoding='utf8')
#调用writer方法,传入CSV文件对象,得到的结果是一个CSVWriter对象
w=csv.writer(file)
#调用CSVWriter对象的writerow方法,一行行的写入数据
w.writerow(['name','age','score','city'])
#还可以调用writerows方法,一次性写入多行数据,但是要求后面的数据还要是一个列表
w.writerows([['zhangsan','18','98','shanghai'],['lisi','20','99','beijing'],['wangwu','17','90','nanjing'],['jerry','19','95','hefei']])
file.close()

2、CSV文件的读取
#以读取方式打开一个CSV文件
file=open('info.csv','r',encoding='utf8',newline='')
#调用CSV模块的reader方法,得到的结果是一个可迭代对象
r = csv.reader(file)
print(type(r))
#对结果进行遍历,获取到结果里的每一行数据
for row in r:
    print(row)
file.close()

标准输入输出

# 将数据写入到内存涉及到 StringIO 和 ByteIO 两个类
除了将数据写入到一个文件以外,我们还可以使用代码,将数据暂时写入到內存里,可以理解为数据缓冲区.Python中提供了 Strings和 Bytes这两个类将字符串数据和二进制数据写入到内存里.

# 将数据写入到内存涉及到 StringIO 和 ByteIO 两个类
from io import StringIO,BytesIO
s_io= StringIO()
s_io.write('hello')#把数据写入到内存缓存起来了
s_io.write('good Morning')

print(s_io.getvalue())
# file 需要的是一个文件流对象
# print('hello',file=open('sss.txt','w'))
print('hello',file=s_io)
print('world',file=s_io)
print('I am',file=s_io)
print('Python',file=s_io)
print(s_io.getvalue())
s_io.close()

b_io=BytesIO()
b_io.write('nihao'.encode('utf8'))
print(b_io.getvalue().decode('utf8'))
b_io.close()

序列化与反序列化

通过文件操作,我们可以将字符串写入到一个本地文件.但是,如果是一个对象(例如列表、字典、元组等),就无法直接写入到一个文件里,需要对这个对象进行序列化,然后才能写入到文件里.
设计一套协议,按照某种规则,把內存中的数据转换为字节序列,保存到文件,这就是序列化,反之,从文件的字节序列恢复到内存中,就是反序列化
Python中提供了JsoN和 pickle两个模块用来实现数据的序列化和反序列化.

JSON模块
JsoN(JavaScriptobjectNotation,JS对象简谱)是一种轻量级的数据交换格式,它基于 ECMAScript的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据.JSON的本质是字符串!
json: 将Python里的数据(str/list/tuple/dict/int/float/bool/None)转换成为对应的json字符串


#序列化:将数据从内存持久化保存到硬盘的过程
#反序列化:将数据从硬盘加载到内存的过程
#write时,只能写入字符串或者二进制
# 字典、列表、数字等都不能直接写入到文件里

#1、将数据转换成为字符串: repr/str  更多我们使用json模块
# json 本质就是字符串,区别在于json里要用双引号来表示字符串

#2、将数据转换成二进制: 使用pickle模块

import json
names=['zhangsan','lisi','jack','tony']
x=json.dumps(names) # dumps 的作用是将数据转换成为字符串
# print(x) #'["zhangsan","lisi","jack","tony"]'
file=open('names.txt','w',encoding='utf8')
file.write(x)
file.close()

#json里将数据持久化有两个方法:
# dumps :将数据转换成为json字符串,不会将数据保存到文件里
# dump :将数据转换成为json字符串的同时写入到指定文件
    eg:json.dump(names,file)
    	file.close

# json 反序列化也有两个方法
# loads: 将json字符串加载成为Python里的数据
# load: 读取文件,把读取的内容加载成为Python里的数据
json.dump(names,file)
file.close()

x='{"name":"zhangsan","age":18}' # 符合json规则的字符串
p=json.loads(x)
print(p, type(p))#{'name':'zhangsan','age':18} <class 'dict'>
print(p['name'])#zhangsan

# load 读取一个文件,并把文件里的json字符串加载成为一个对象(以前文件内容是什么类型,反序列化后就是什么类型)
file1=open('names.txt','r',encoding='utf8')#打开文件
y=json.load(file1)
print(y)
file1.close()

异常处理

异常处理方法

在程序执行过程中,由于编码不规范等造成程序无法正常执行,此时程序就会报错,也即考虑程序的健壮性(很多语言都具有异常处理机制

def div(a,b):
    return a/b
try:
    x=div(5,0)
    print('hehehe')#如果程序报错了,这句话就不会执行
except Exception as e: #如果程序出错了,会立刻跳转到except语句
    print('程序出错了!!!')
else:
    print('计算的结果是')

上面使用到了try……except语句用来处理程序运行过程中的异常

fiel=open('ddd.txt')
print(file.read())
file.close()

#因为ddd.txt 文件并不存在,于是我们知道上面的语句会报错,执行时会在file=open('ddd.txt')处报错,这个时候就显示出异常处理的作用了,他会防止程序一错再错,导致很多不必要的报错
#于是我们采用以下的方法来进行:
try:
    file = open('ddd.txt')
	print(file.read())
    file.close()
except Exception as e: #给异常信息起了一个变量名(别名) 叫 e
    print(type(e))
    print(e)

# 程序没有报错,返回程序错误信息 ,结果如下:
# <class 'FileNotFoundError'>
# [Errno 2] No such file or directory: 'ddd.txt'

看到FileNotFoundError,可以想到还有很多其他类型的报错,如:1/0 ==> ZeroDivisionError
看下面的程序:
try:
    1 / 0
    file=open('ddd.txt')
    print(file.read())
    file.close()
except FileNotFoundError as e:
    print('出错了'+str(e))
#这个程序会直接崩溃,原因是except 只是指定FileNotFoundError,但是该程序的第一个错误是ZeroDivisionErrorZ,如果需要同时检查ZeroDivisionError和FileNotFoundError,可以使用:except (FileNotFoundError,ZeroDivisionError) as e:  用元组的形式把需要异常处理的报错类型放在一起即可,但是程序执行过程中还是会按照从上到下的先后顺序来判断首先是那个类型的错误导致程序结束运行
#使用 except Exception as e: 或者就一个 except:  可以把程序中任何一个首先报错的类型赋值给 e ,不需要我们自己来判断 Exception相当于所有报错子类的爹(父类)

异常的使用场景

age = input('请输入您的年龄:')
try:
    age = float(age) # 这里先判断转换过程中是否有 ValueError,如果有就结束程序,反之继续判断
except ValueError as e:
    print('输入的不是数字')
else:
    if age > 18:
        print('欢迎来到我的网站')
    else:
        print('未满18周岁,请主动离开')

练习

# 定义一个点类pointer
# 属性是横向坐标x与纵向坐标y
# 定义有圆心点cp与半径radius
# 方法有:
# 1、求圆的面积
# 2、求圆的周长
# 3、求指定点与圆的关系(圆内,圆外,圆上)
# 4、设计到的数学公式:指定点与圆心之间的距离与圆的半径进行比较
# 个人题解
import math


class Pointer(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    # @staticmethod
    def get_distance(self, m, n):
        return ((m.x - n.x) ** 2 + (m.y - n.y) ** 2) ** (1 / 2)

    # @staticmethod
    def relationship(self, a, b):  # 定义a是点,b是圆
        relation = a.get_distance(a, b.cp)
        if relation < b.radius:
            print("点(%d,%d)在圆内" % (a.x, a.y))
        elif relation == b.radius:
            print('点(%d,%d)在圆上' % (a.x, a.y))
        else:
            print('点(%d,%d)在圆外' % (a.x, a.y))


class Circle(object):
    def __init__(self, cp, radius):
        self.cp = cp
        self.radius = radius

    def get_length(self):
        return math.pi * 2 * self.radius

    def get_area(self):
        return math.pi * self.radius ** 2


p = Pointer(0, 0)  # 创建了一个Pointer对象
c = Circle(p, 3)  # 创建好的Pointer对象传递给Circle,同时创建了一个Circle对象
print(hex(id(p)), hex(id(c)))  # 打印p和c的内存地址
print(c.get_area())
print(c.get_length())
a = int(input('请输入需要判断的点的横坐标'))
b = int(input('请输入需要判断的点的纵坐标'))
q = Pointer(a, b)
print(q.get_distance(p, q))
q.relationship(q, c)

finally关键字的使用

file = open('D:/Videos/Captures/寄明月_洛天依.mp4', 'rb')try:    while True:        content = file.read(1024)        if not content:            break        print(content)finally:  # 最终都会被执行的代码    file.close()    print('文件被关闭了')
def test(a, b):    x = a + b    return x  # 一旦return就表示函数结束    # return 'hello' # 这段代码不会被执行,一般情况下一个函数最多只能执行一个return语句,
def demo1(a, b):    try:        x = a / b    except ZeroDivisionError:        return '除数不能为0'    return x    # 除数不能为0def demo2(a, b):    try:        x = a / b    except ZeroDivisionError:        print('除数不能为0')    else:        return x    finally:        return 'hello,finally 走了'# 如果函数里有finally,finally里的返回值就会覆盖之前的返回值    # 除数不能为0    # None# print(demo1(1, 2))print(demo2(1, 2))

with 关键字的使用

基本使用

try:
    file = open('pic.py', 'r', encoding='utf8')
except FileNotFoundError:
    print('文件不存在')
else:
    try:
        file.read()
    finally:
        file.close()
        
        
 try:
    with open('pic.py', 'r', encoding='utf8') as file:
        file.read()  # 不需要再手动的关闭文件
        # file.close() with 关键字会帮助我们关闭这个 文件,但是他不会判断文件是否存在的问题,这个仍然需要我们自己来解决
except FileNotFoundError:
    print('文件不存在')

with 我们称之为上下文管理器,很多需要手动关闭的连接

比如说 文件连接,socket连接,数据库对接连接,都能使用with关键字自动关闭连接

with 关键字后面对象需要实现__enter__ 和 __exit__魔法方法

with 语句后面的结果对象,需要重写__enter__和 __exit__方法,当进入到with代码块时,会自动调用__enter__方法里的代码

当with代码块执行完成以后,会自动调用__exit__方法

上下文管理

class Demo(object):
    def __enter__(self):
        print('__enter__方法被执行了')
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__方法被调用了')


def create_obj():
    x= Demo()
    return x

# y=create_obj()
# d=y.__enter__()
with create_obj() as d:  # as 变量名,这条语句的作用和上面两条语句的作用一样
    print(d) # 变量 d 不是 create_obj 的返回结果,它是创建的对象x调用__enter__之后的返回结果
    print(type(d))

自定义异常

# 系统内置的异常:  ZeroDivisionError FileNotFoundError  FileExistsError ValueError KeyError SyntaxError等很多
# 要求:让用户输入用户名和密码,如果用户名和密码长度均为6-12位则正确,否则错误
class LengthError(Exception):
    def __int__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return '长度条件不符合'


passwd = input('请输入您的密码:')
m = 6
n = 12
if m <= len(passwd) <= n:
    print('密码格式正确')
else:
    raise LengthError(m, n)
print('将密码保存到数据库中了')

装饰器的高级使用

调用can_play函数,将12传递给clock
再调用handle_action方法,把play_game传递给fn
接着再调用play_game,其实调用的就是do_action

def can_play(clock):
    print('最外层函数被调用了,clock={}'.format(clock))

    def handle_action(fn):
        def do_action(name, game):
            if clock < 21:
                fn(name, game)
            else:
                print('太晚了,不能玩游戏了')

        return do_action

    return handle_action


@can_play(22) # 装饰器函数带参数
def play_game(name, game):
    print(name + '正在玩' + game)


play_game('张三', '王者荣耀')

可迭代器

from collections.abc import Iterable


# 可迭代对象:已经见到过很多的可迭代对象,list/tuple/dict/set/str/range/filter/map
# for...in 可迭代对象
class Foo(object):
    def __next__(self):
        return 1


class demo(object):
    def __init__(self, x):
        self.x = x

    def __iter__(self):  # 只要重写了__iter__方法,那么这个类建立的对象就是一个可迭代对象
        f = Foo()
        return f


d = demo()
print(isinstance(d, Iterable))  # isinstance:用来判断一个实例对象是否是有指定的类创建出来的
names = list(('zhangsan', 'lisi'))
# 以上两者没什么本质区别,这里不是list强转,而是new了一个list对象
print(isinstance(names, Iterable))  # True
# for...in循环的本质就是调用可迭代对象的__iter__方法,获取到这个方法的返回值
#     这个返回值需要是一个迭代器对象,然后再调用这个对象的__next__方法

for x in d:
    print(x)
from collections.abc import Iterable
# 可迭代对象:已经见到过很多的可迭代对象,list/tuple/dict/set/str/range/filter/map
# for...in 可迭代对象
class DD(object):
    def __init__(self, x):
        self.x = x
        self.count=0

    def __iter__(self):  # 只要重写了__iter__方法,那么这个类建立的对象就是一个可迭代对象
        return self
    def __next__(self):
        # 每一次for...in 循环都会调用一次__next__方法,获取返回值
        self.count+=1
        if self.count<=self.x:
            return 'hello'
        else:
            raise StopIteration  #让迭代器停止


# d = demo(10)
for i in DD(10):
    print(i)
# print(isinstance(d, Iterable))  # isinstance:用来判断一个实例对象是否是有指定的类创建出来的
names = list(('zhangsan', 'lisi'))
# 以上两者没什么本质区别,这里不是list强转,而是new了一个list对象
print(isinstance(names, Iterable))  # True
# for...in循环的本质就是调用可迭代对象的__iter__方法,获取到这个方法的返回值
#     这个返回值需要是一个迭代器对象,然后再调用这个对象的__next__方法

迭代器的使用

# 使用迭代器生成斐波那契数列
class Fibonacci(object):
    def __init__(self, n):
        self.n = n
        self.count = 1
        self.num1 = 0
        self.num2 = 1

    def __iter__(self):
        return self

    def __next__(self):
        if self.count <= self.n:
            self.count += 1
            self.num1, self.num2 = self.num2, self.num1 + self.num2
            return self.num1
        else:
            raise StopIteration
f = Fibonacci(12)  #这种类型就是占时间但是不占用很大的空间
for i in f:
    print(i)
# 既然有列表了,为什么还要有生成器呢?
nums=[1,2,3,4,5,6,7,8,9,10]# 这种是占用很大的空间,但是不需要多少时间
x=range(10)

正则表达式

#用来处理字符串,对字符串进行检索和替换的
# 1、查找 2、替换
import re
x='hello\world'
print(x)
# 在正则表达式中,如果想要匹配一个  需要使用 \\
# 第一个 参数就是正则表达式匹配规则,第二个参数表示需要匹配的字符串
m=re.match('\\',x) # match 和 search
s=re.search('\\',x)
s2=re.search(r'\',x) # 还可以在字符串前面加r,\就表示
#search 和match方法执行结果是一个Match类型的对象
print(m)# None
print(s)# <re.Match object; span=(5,6),match='\'>

正则查找相关方法

match: 查找字符串,返回的结果是一个re.Match对象
search:查找字符串,返回的结果是一个re.Match对象
match 和 search 共同点:1、只对字符串查询一次,2、返回值类型都是 re。Match类型的对象
match search 不同点: match必须是从头(第一个字符)开始匹配,一旦匹配失败,就返回None;search是在整个字符串里匹配
finditer: 返回的结果是一个可迭代对象,查找到所有的匹配对象,然后把结果返回到一个可迭代对象里
findall: 把查找到的所有的字符串结果放到一个列表里
fullmatch: 完整匹配,字符串需要完全满足规则才会有结果
import re
from collections.abc import Iterable

m1 = re.match(r'hel', 'hello world good moring ')
print(m1)  # <re.Match object; span=(0, 3), match='hel'> 从0开始,但是不包含3,也就是第4个
m2 = re.search(r'hel', 'hello world good moring ')
print(m2)  # <re.Match object; span=(0, 3), match='hel'>
m3 = re.match(r'good', 'hello world good moring ')
print(m3)  # None
m4 = re.search(r'good', 'hello world good moring ')
print(m4)  # <re.Match object; span=(12, 16), match='good'>
m5=re.finditer(r'x', 'sfkxslaxfklsx') #print(m5) <callable_iterator object at 0x000001E70FABA730>
print(isinstance(m5, Iterable))
for i in m5:
    print(i)
m6=re.findall(r'x','sqzxfsxxwxxxewx')
print(m6) # ['x', 'x', 'x', 'x', 'x', 'x', 'x']

m7=re.fullmatch(r'hello','hello world')
print(m7) # None
m8 = re.fullmatch(r'h.*d', 'hello world')
print(m8)  # <re.Match object; span=(0, 11), match='hello world'>

re.Match类的使用

调用re.match re.search 或者对 re.finditer 结果进行遍历,拿到的内容都是re.Match类型的对象

import re
re.search(r'm','o3rjomjadas')
print(m)
import re
m=re.search(r'm.*a','o3rjomjadas')
print(m) # <re.Match object; span=(5, 6), match='m'>
print(m.__dir__())
# ['__repr__', '__getitem__', 'group', 'start', 'end', 'span', 'groups', 'groupdict', 'expand',
# '__copy__', '__deepcopy__', 'string', 're', 'pos', 'endpos', 'lastindex', 'lastgroup', 'regs',
# '__doc__', '__hash__', '__str__', '__getattribute__', '__setattr__', '__delattr__', '__lt__',
# '__le__', '__eq__', '__ne__', '__gt__', '__ge__', '__init__', '__new__', '__reduce_ex__',
# '__reduce__', '__subclasshook__', '__init_subclass__', '__format__', '__sizeof__', '__dir__', '__class__']
print(m.pos) # 0
print(m.pos, m.endpos)
print(len('o3rjomjadas'))
print(m.span()) #(5, 10)匹配到的结果字符串的开始和结束下标

# 使用group方法可以获取到匹配的字符串结果
# group 可以传参,表示第n个分组
print(m.group()) # mjada
print(m.group(0)) # mjada
print(m.group(1)) # IndexError: no such group

# group 方法表示正则表达式的分组
# 1、在正则表达式里使用() 表示一个分组
# 2、如果没有分组,默认只有一组
# 3、分组的下表从0开始
# 下面的正则表达式有4个分组
m1=re.search(r'(9.*)(0.*)(5.*7)','da9fi0riel5kfsda7ifsdaiferit')
# 分组0:(9.*)(0.*)(5.*7)
# 第1分组:(9.*)
# 第2分组:(0.*)
# 第3分组:(5.*7)
print(m1.group()) # 第0组就是把整个正则表达式当作一个整体,默认就是第0组
print(m1.group(1)) # 第1组 9fi
print(m1.group(2)) # 第2组 0riel
print(m1.group(3)) # 第3组 5kfsda7
print(m1.groups()) # ('9fi', '0riel', '5kfsda7')

# groupdict 作用是获取到分组组成的字典
print(m1.groupdict()) # {}
# (?P<name>表达式) 可以给分组起一个名字
m2=re.search(r'(9.*)(?P<xxx>0.*)(5.*7)','da9fi0riel5kfsda7ifsdaiferit')
print(m2.groupdict()) # {'xxx': '0riel'}
print(m2.groupdict('xxx')) # {'xxx': '0riel'}
# 可以通过分组名或者分组的下标获取到分组里面匹配到的字符串
print(m2.group('xxx'))
print(m2.group(2))

re.compile方法的使用

import re

# compile 编译
# 在re 在re模块里,可以使用re.方法调用函数,还可以调用re.compile得到一个对象
# 可以直接调用re.search 方法
m = re.search(r'm.*a', 'o3rjomjadas')
print(m)  # <re.Match object; span=(5, 10), match='mjada'>
# 下面两条语句的结果和上面一条语句的结果是一样的
r = re.compile(r'm.*a')  # 结果是一个对象
x = r.search('o3rjomjadas')
print(x)  # <re.Match object; span=(5, 10), match='mjada'>
# 同样可以推广到 re.match() re.findall() re.finditer()

正则修饰符

import re

# . 表示除了换行意外的任意字符
# re.S : 让 . 可以匹配到换行符 n
# re。I : 忽略大小写
# re.M : 多行匹配,影响^和$
x=re.search(r'm.*a','safmsofnsjoasdlel')
print(x) # None
x=re.search(r'm.*a','safmsofnsjoasdlel',re.S)
print(x) # <re.Match object; span=(3, 12), match='msofnsjoa'>
y=re.search(r'x','good Xyz')
print(y) # None

# w :表示的是字母数字和_  +. 出现一次以上   $ :以指定的内容结尾
z=re.findall(r'w+$','i am boyn you are girln hi is man')
print(z) # ['man']

z=re.findall(r'w+$','i am boyn you are girln hi is man',re.M)
print(z) # ['boy', 'girl', 'man']

正则匹配规则

import re

# 1、数字和字母都表示它本身
# 如下两例
re.search(r'x', 'hello xyz')
re.search(r'2', 'hel2lo xyz')

# 2、很多字母前面添加 会有特殊含义(重点)
print(re.search(r'd', 'good'))  # 普通字母d
print(re.search(r'd', 'good'))  # d 特殊含义,不再表示字母d了
print(re.search(r'd', 'wsdf2532sf'))

# 3、绝大多数标点符号都有特殊含义 (重点)
# re.search(r'+','1+2') 不能直接使用

# 4、如果想要使用标点符号,需要加  转义
print(re.search(r'+', '1+2'))

# s 表示任意的空白字符
print(re.search(r's', 'hello world'))  # <re.Match object; span=(5, 6), match=' '> 空格
print(re.search(r's', 'hellonworld'))  # <re.Match object; span=(5, 6), match='n'> 换行
print(re.search(r's', 'hellotworld'))  # <re.Match object; span=(5, 6), match='t'> 制表符
# S 表示非空白字符
print(re.search(r'S', 'tn  x'))  # <re.Match object; span=(4, 5), match='x'>

# 标点符号的使用
# ()表示一个分组
m = re.search(r'h(d+)x', 'sh829xkflsa')
print(m.group())

喜欢 (0)