1. 程式人生 > 其它 >Python檔案處理、異常處理、finally、with、裝飾器、可迭代器、正則表示式

Python檔案處理、異常處理、finally、with、裝飾器、可迭代器、正則表示式

檔案處理

檔案操作:
#開啟檔案
#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','safmsof\nsjoasdlel')
print(x) # None
x=re.search(r'm.*a','safmsof\nsjoasdlel',re.S)
print(x) # <re.Match object; span=(3, 12), match='msof\nsjoa'>
y=re.search(r'x','good Xyz')
print(y) # None

# \w :表示的是字母數字和_  +. 出現一次以上   $ :以指定的內容結尾
z=re.findall(r'\w+$','i am boy\n you are girl\n hi is man')
print(z) # ['man']

z=re.findall(r'\w+$','i am boy\n you are girl\n 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', 'hello\nworld'))  # <re.Match object; span=(5, 6), match='\n'> 換行
print(re.search(r'\s', 'hello\tworld'))  # <re.Match object; span=(5, 6), match='\t'> 製表符
# \S 表示非空白字元
print(re.search(r'\S', '\t\n  x'))  # <re.Match object; span=(4, 5), match='x'>

# 標點符號的使用
# ()表示一個分組
m = re.search(r'h(\d+)x', 'sh829xkflsa')
print(m.group())
生命依靠吸收負熵,避免了趨向平衡的衰退